From a7fa4184c9ae744eada81db411874eb6e72044d7 Mon Sep 17 00:00:00 2001 From: abrignoni Date: Sun, 24 Apr 2022 00:12:28 -0400 Subject: [PATCH] iLTriage All requested changes --- ileappGUI.py | 8 +- scripts/artifacts/FacebookMessenger.py | 203 ---- scripts/artifacts/NotificationParams.txt | 49 - scripts/artifacts/accs.py | 48 - scripts/artifacts/addressBook.py | 57 - scripts/artifacts/airtags.py | 200 ---- scripts/artifacts/alarms.py | 76 -- scripts/artifacts/appConduit.py | 84 -- scripts/artifacts/appGrouplisting.py | 43 - scripts/artifacts/appItunesmeta.py | 68 -- scripts/artifacts/appSnapshots.py | 93 -- scripts/artifacts/appleMapsApplication.py | 38 - scripts/artifacts/appleMapsGroup.py | 49 - scripts/artifacts/appleMapsSearchHistory.py | 46 - scripts/artifacts/applePodcasts.py | 98 -- scripts/artifacts/appleWalletCards.py | 78 -- scripts/artifacts/appleWalletPasses.py | 69 -- scripts/artifacts/appleWalletTransactions.py | 50 - scripts/artifacts/appleWifiPlist.py | 265 ----- scripts/artifacts/applicationstate.py | 73 -- scripts/artifacts/artGlobals.py | 2 +- scripts/artifacts/bluetooth.py | 142 --- scripts/artifacts/cacheRoutesGmap.py | 45 - scripts/artifacts/calendarAll.py | 117 -- scripts/artifacts/callHistory.py | 70 -- scripts/artifacts/cashApp.py | 77 -- scripts/artifacts/celWireless.py | 47 - scripts/artifacts/cloudkitParticipants.py | 74 -- scripts/artifacts/cloudkitSharing.py | 136 --- scripts/artifacts/conDev.py | 62 -- scripts/artifacts/confaccts.py | 27 - scripts/artifacts/deviceActivator.py | 64 -- scripts/artifacts/dhcphp.py | 45 - scripts/artifacts/dhcpl.py | 42 - scripts/artifacts/discordAcct.py | 68 -- scripts/artifacts/discordJson.py | 136 --- scripts/artifacts/discordManifest.py | 36 - scripts/artifacts/filesAppsclient.py | 53 - scripts/artifacts/filesAppsdb.py | 82 -- scripts/artifacts/filesAppsm.py | 71 -- scripts/artifacts/geodApplications.py | 46 - scripts/artifacts/geodMapTiles.py | 133 --- scripts/artifacts/geodPDPlaceCache.py | 48 - scripts/artifacts/googleDuo.py | 163 --- scripts/artifacts/iCloudWifi.py | 65 -- scripts/artifacts/icloudMeta.py | 64 -- scripts/artifacts/icloudPhotoMeta.py | 167 --- scripts/artifacts/icloudSharedalbums.py | 161 --- scripts/artifacts/iconsScreen.py | 57 - scripts/artifacts/imoHD_Chat.py | 148 --- scripts/artifacts/instagramThreads.py | 182 --- scripts/artifacts/interactionCcontacts.py | 105 -- scripts/artifacts/keyboardAppUsage.py | 33 - scripts/artifacts/keyboardLexicon.py | 53 - scripts/artifacts/kikBplistmeta.py | 69 -- scripts/artifacts/kikMessages.py | 117 -- scripts/artifacts/kikPendingUploads.py | 85 -- scripts/artifacts/kikUsersgroups.py | 79 -- scripts/artifacts/locServicesconfig.py | 109 -- scripts/artifacts/mailprotect.py | 214 ---- scripts/artifacts/mediaLibrary.py | 112 -- scripts/artifacts/medicalID.py | 51 - scripts/artifacts/mobileActivationLogs.py | 75 -- scripts/artifacts/mobileBackup.py | 46 - scripts/artifacts/mobileContainerManager.py | 50 - scripts/artifacts/mobileInstall.py | 634 ----------- scripts/artifacts/notes.py | 104 -- scripts/artifacts/notificationsXI.py | 336 ------ scripts/artifacts/notificationsXII.py | 104 -- scripts/artifacts/ooklaSpeedtestData.py | 174 --- scripts/artifacts/photosMetadata.py | 1037 ------------------ scripts/artifacts/protonMail.py | 256 ----- scripts/artifacts/queryPredictions.py | 48 - scripts/artifacts/quickLook.py | 52 - scripts/artifacts/recentApphistory.py | 40 - scripts/artifacts/reminders.py | 51 - scripts/artifacts/restoreLog.py | 206 ---- scripts/artifacts/routineD.py | 125 +++ scripts/artifacts/safariBookmarks.py | 49 - scripts/artifacts/safariFavicons.py | 60 - scripts/artifacts/safariRecentWebSearches.py | 38 - scripts/artifacts/safariTabs.py | 55 - scripts/artifacts/safariWebsearch.py | 65 -- scripts/artifacts/script.txt | 46 - scripts/artifacts/slack.py | 339 ------ scripts/artifacts/tcc.py | 60 - scripts/artifacts/teams.py | 246 ----- scripts/artifacts/teamsSegment.py | 139 --- scripts/artifacts/textinputTyping.py | 68 -- scripts/artifacts/tikTok.py | 110 -- scripts/artifacts/tileApp.py | 58 - scripts/artifacts/tileAppDb.py | 63 -- scripts/artifacts/tileAppDisc.py | 51 - scripts/artifacts/tileAppNetDb.py | 53 - scripts/artifacts/venmo.py | 177 --- scripts/artifacts/viber.py | 693 ------------ scripts/artifacts/voiceRecordings.py | 65 -- scripts/artifacts/voiceTriggers.py | 64 -- scripts/artifacts/walStrings.py | 63 -- scripts/artifacts/weatherAppLocations.py | 50 - scripts/artifacts/webClips.py | 72 -- scripts/artifacts/whatsappContacts.py | 61 -- scripts/artifacts/whatsappMessages.py | 117 -- scripts/artifacts/wiLoc.py | 53 - scripts/html_parts.py | 8 +- scripts/ilap_artifacts.py | 200 +--- scripts/report.py | 8 +- scripts/version_info.py | 30 +- 108 files changed, 144 insertions(+), 11707 deletions(-) delete mode 100644 scripts/artifacts/FacebookMessenger.py delete mode 100644 scripts/artifacts/NotificationParams.txt delete mode 100644 scripts/artifacts/accs.py delete mode 100644 scripts/artifacts/addressBook.py delete mode 100644 scripts/artifacts/airtags.py delete mode 100644 scripts/artifacts/alarms.py delete mode 100644 scripts/artifacts/appConduit.py delete mode 100644 scripts/artifacts/appGrouplisting.py delete mode 100644 scripts/artifacts/appItunesmeta.py delete mode 100644 scripts/artifacts/appSnapshots.py delete mode 100644 scripts/artifacts/appleMapsApplication.py delete mode 100644 scripts/artifacts/appleMapsGroup.py delete mode 100644 scripts/artifacts/appleMapsSearchHistory.py delete mode 100644 scripts/artifacts/applePodcasts.py delete mode 100644 scripts/artifacts/appleWalletCards.py delete mode 100644 scripts/artifacts/appleWalletPasses.py delete mode 100644 scripts/artifacts/appleWalletTransactions.py delete mode 100644 scripts/artifacts/appleWifiPlist.py delete mode 100644 scripts/artifacts/applicationstate.py delete mode 100644 scripts/artifacts/bluetooth.py delete mode 100644 scripts/artifacts/cacheRoutesGmap.py delete mode 100644 scripts/artifacts/calendarAll.py delete mode 100644 scripts/artifacts/callHistory.py delete mode 100644 scripts/artifacts/cashApp.py delete mode 100644 scripts/artifacts/celWireless.py delete mode 100644 scripts/artifacts/cloudkitParticipants.py delete mode 100644 scripts/artifacts/cloudkitSharing.py delete mode 100644 scripts/artifacts/conDev.py delete mode 100644 scripts/artifacts/confaccts.py delete mode 100644 scripts/artifacts/deviceActivator.py delete mode 100644 scripts/artifacts/dhcphp.py delete mode 100644 scripts/artifacts/dhcpl.py delete mode 100644 scripts/artifacts/discordAcct.py delete mode 100644 scripts/artifacts/discordJson.py delete mode 100644 scripts/artifacts/discordManifest.py delete mode 100644 scripts/artifacts/filesAppsclient.py delete mode 100644 scripts/artifacts/filesAppsdb.py delete mode 100644 scripts/artifacts/filesAppsm.py delete mode 100644 scripts/artifacts/geodApplications.py delete mode 100644 scripts/artifacts/geodMapTiles.py delete mode 100644 scripts/artifacts/geodPDPlaceCache.py delete mode 100644 scripts/artifacts/googleDuo.py delete mode 100644 scripts/artifacts/iCloudWifi.py delete mode 100644 scripts/artifacts/icloudMeta.py delete mode 100644 scripts/artifacts/icloudPhotoMeta.py delete mode 100644 scripts/artifacts/icloudSharedalbums.py delete mode 100644 scripts/artifacts/iconsScreen.py delete mode 100644 scripts/artifacts/imoHD_Chat.py delete mode 100644 scripts/artifacts/instagramThreads.py delete mode 100644 scripts/artifacts/interactionCcontacts.py delete mode 100644 scripts/artifacts/keyboardAppUsage.py delete mode 100644 scripts/artifacts/keyboardLexicon.py delete mode 100644 scripts/artifacts/kikBplistmeta.py delete mode 100644 scripts/artifacts/kikMessages.py delete mode 100644 scripts/artifacts/kikPendingUploads.py delete mode 100644 scripts/artifacts/kikUsersgroups.py delete mode 100644 scripts/artifacts/locServicesconfig.py delete mode 100644 scripts/artifacts/mailprotect.py delete mode 100644 scripts/artifacts/mediaLibrary.py delete mode 100644 scripts/artifacts/medicalID.py delete mode 100644 scripts/artifacts/mobileActivationLogs.py delete mode 100644 scripts/artifacts/mobileBackup.py delete mode 100644 scripts/artifacts/mobileContainerManager.py delete mode 100644 scripts/artifacts/mobileInstall.py delete mode 100644 scripts/artifacts/notes.py delete mode 100644 scripts/artifacts/notificationsXI.py delete mode 100644 scripts/artifacts/notificationsXII.py delete mode 100644 scripts/artifacts/ooklaSpeedtestData.py delete mode 100644 scripts/artifacts/photosMetadata.py delete mode 100644 scripts/artifacts/protonMail.py delete mode 100644 scripts/artifacts/queryPredictions.py delete mode 100644 scripts/artifacts/quickLook.py delete mode 100644 scripts/artifacts/recentApphistory.py delete mode 100644 scripts/artifacts/reminders.py delete mode 100644 scripts/artifacts/restoreLog.py create mode 100644 scripts/artifacts/routineD.py delete mode 100644 scripts/artifacts/safariBookmarks.py delete mode 100644 scripts/artifacts/safariFavicons.py delete mode 100644 scripts/artifacts/safariRecentWebSearches.py delete mode 100644 scripts/artifacts/safariTabs.py delete mode 100644 scripts/artifacts/safariWebsearch.py delete mode 100644 scripts/artifacts/script.txt delete mode 100644 scripts/artifacts/slack.py delete mode 100644 scripts/artifacts/tcc.py delete mode 100644 scripts/artifacts/teams.py delete mode 100644 scripts/artifacts/teamsSegment.py delete mode 100644 scripts/artifacts/textinputTyping.py delete mode 100644 scripts/artifacts/tikTok.py delete mode 100644 scripts/artifacts/tileApp.py delete mode 100644 scripts/artifacts/tileAppDb.py delete mode 100644 scripts/artifacts/tileAppDisc.py delete mode 100644 scripts/artifacts/tileAppNetDb.py delete mode 100644 scripts/artifacts/venmo.py delete mode 100644 scripts/artifacts/viber.py delete mode 100644 scripts/artifacts/voiceRecordings.py delete mode 100644 scripts/artifacts/voiceTriggers.py delete mode 100644 scripts/artifacts/walStrings.py delete mode 100644 scripts/artifacts/weatherAppLocations.py delete mode 100644 scripts/artifacts/webClips.py delete mode 100644 scripts/artifacts/whatsappContacts.py delete mode 100644 scripts/artifacts/whatsappMessages.py delete mode 100644 scripts/artifacts/wiLoc.py diff --git a/ileappGUI.py b/ileappGUI.py index 24d6f5e2..da0bc58b 100644 --- a/ileappGUI.py +++ b/ileappGUI.py @@ -74,7 +74,7 @@ def pickModules(): mlist.append( CheckList(val[0] + f' [{key}]', indx, key, disabled) ) indx = indx + 1 -sg.theme('DarkAmber') # Add a touch of color +sg.theme('DarkTeal4') # Add a touch of color # All the stuff inside your window. normal_font = ("Helvetica", 12) @@ -84,8 +84,8 @@ def pickModules(): GuiWindow.progress_bar_total = len(ileapp.tosearch) -layout = [ [sg.Text('iOS Logs, Events, And Plists Parser', font=("Helvetica", 22))], - [sg.Text('https://github.com/abrignoni/iLEAPP', font=("Helvetica", 14))], +layout = [ [sg.Text('iLTriage', font=("Helvetica", 22))], + [sg.Text('https://github.com/22WEAT4N6/iLTriage', font=("Helvetica", 14))], [sg.Frame(layout=[ [sg.Input(size=(97,1)), sg.FileBrowse(font=normal_font, button_text='Browse File', key='INPUTFILEBROWSE'), @@ -104,7 +104,7 @@ def pickModules(): [sg.Submit('Process',font=normal_font), sg.Button('Close', font=normal_font)] ] # Create the Window -window = sg.Window(f'iLEAPP version {aleapp_version}', layout) +window = sg.Window(f'iLTriage version {aleapp_version}', layout) GuiWindow.progress_bar_handle = window['PROGRESSBAR'] diff --git a/scripts/artifacts/FacebookMessenger.py b/scripts/artifacts/FacebookMessenger.py deleted file mode 100644 index 32a5fce7..00000000 --- a/scripts/artifacts/FacebookMessenger.py +++ /dev/null @@ -1,203 +0,0 @@ -import sqlite3 -import textwrap - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, get_next_unused_name, open_sqlite_db_readonly - -def get_FacebookMessenger(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - if not file_found.endswith('.db'): - continue # Skip all other files - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - datetime(thread_messages.timestamp_ms/1000,'unixepoch') as Timestamp, - contacts.name as 'Sender Name', - thread_messages.thread_key, - thread_messages.text as 'Message', - case thread_messages.has_attachment - when NULL then '' - when 1 then 'Yes' - end as Attachment, - attachments.filename as 'Attachment Name', - attachments.filesize as 'Attachment Size', - attachment_items.title_text - from thread_messages - left join contacts - on thread_messages.sender_id = contacts.id - left join attachments - on thread_messages.message_id = attachments.message_id - left join attachment_items - on thread_messages.message_id = attachment_items.message_id - where attachment_items.title_text IS NULL or attachment_items.title_text like 'Location sharing ended' - order by Timestamp - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Facebook Messenger - Chats') - report.start_artifact_report(report_folder, 'Facebook Messenger - Chats') - report.add_script() - data_headers = ('Timestamp','Sender Name','Sender ID','Message','Attachment','Attachment Name','Attachment Size','Title Text') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Facebook Messenger - Chats' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Facebook Messenger - Chats' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Facebook Messenger - Chats data available') - - cursor.execute(''' - select - datetime(thread_messages.timestamp_ms/1000,'unixepoch') as Timestamp, - contacts.name as 'Sender Name', - thread_messages.thread_key, - attachments.title_text as "Call Type", - attachments.subtitle_text as "Duration/Subtitle" - from thread_messages - left join contacts - on thread_messages.sender_id = contacts.id - left join attachments - on thread_messages.message_id = attachments.message_id - where attachments.title_text like 'Audio Call' or attachments.title_text like 'Video Chat' - order by Timestamp - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Facebook Messenger - Calls') - report.start_artifact_report(report_folder, 'Facebook Messenger - Calls') - report.add_script() - data_headers = ('Timestamp','Sender Name','Sender ID','Call Type','Call Duration/Subtitle') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Facebook Messenger - Calls' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Facebook Messenger - Calls' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Facebook Messenger - Calls data available') - - cursor.execute(''' - select - id, - name, - normalized_name_for_search, - profile_picture_url, - case is_messenger_user - when 0 then '' - when 1 then 'Yes' - end as is_messenger_user - from contacts - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Facebook Messenger - Contacts') - report.start_artifact_report(report_folder, 'Facebook Messenger - Contacts') - report.add_script() - data_headers = ('User ID','Username','Normalized Username','Profile Pic URL','Is App User') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Facebook Messenger - Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Facebook Messenger - Contacts' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Facebook Messenger - Contacts data available') - - cursor.execute(''' - select - datetime(secure_messages.timestamp_ms/1000,'unixepoch') as 'Timestamp', - secure_messages.thread_key, - contacts.name as 'Sender', - secure_messages.text, - secure_messages.secure_message_attachments_encrypted - from secure_messages - left join contacts - on secure_messages.sender_id = contacts.id - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Facebook Messenger - Secret Conversation') - report.start_artifact_report(report_folder, 'Facebook Messenger - Secret Conversation') - report.add_script() - data_headers = ('Timestamp','Thread Key','Sender Name','Message (Encrypted)', 'Attachment (Encrypted)') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Facebook Messenger - Secret Conversation' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Facebook Messenger - Secret Conversation' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Facebook Messenger - Secret Conversation data available') - - cursor.execute(''' - select - datetime(threads.last_activity_timestamp_ms/1000,'unixepoch'), - thread_participant_detail.thread_key, - group_concat(thread_participant_detail.name, ';') - from thread_participant_detail - join threads - on threads.thread_key = thread_participant_detail.thread_key - group by thread_participant_detail.thread_key - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Facebook Messenger - Conversation Groups') - report.start_artifact_report(report_folder, 'Facebook Messenger - Conversation Groups') - report.add_script() - data_headers = ('Timestamp (Last Activity)','Thread Key','Thread Participants') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Facebook Messenger - Conversation Groups' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Facebook Messenger - Conversation Groups' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Facebook Messenger - Conversation Groups data available') - - db.close() - return diff --git a/scripts/artifacts/NotificationParams.txt b/scripts/artifacts/NotificationParams.txt deleted file mode 100644 index 1bf0471d..00000000 --- a/scripts/artifacts/NotificationParams.txt +++ /dev/null @@ -1,49 +0,0 @@ -AppNotificationMessage -CriticalAlertSound -ShouldHideTime -AppNotificationMessageLocalizationArguments -ShouldSuppressSyncDismissalWhenRemoved -ToneAlertType -BadgeApplicationIcon -UNNotificationNotificationCenterDestination -ShouldHideDate -ShouldPreventNotificationDismissalAfterDefaultAction -AppNotificationIdentifier -ShouldIgnoreDowntime -AppNotificationSummaryArgumentCount -TriggerRepeats -AppNotificationMessageLocazationKey -UNNotificationUserInfo -SoundMaximumDuration -AppNotificationCreationDate -UNNotificationDefaultDestinations -UNNotificationAlertDestination -ShouldSuppressScreenLightUp -SoundShouldRepeat -SoundShouldIgnoreRingerSwitch -AppNotificationBadgeNumber -HasDefaultActionKey -ShouldPresentAlert -ShouldPlaySound -UNNotificationCarPlayDestination -ShouldIgnoreDoNotDisturb -TriggerTimeInterval -UNNotificationLockScreenDestination -ToneMediaLibraryItemIdentifier -ShouldBackgroundDefaultAction -AppNotificationContentAvailable -ShouldAuthenticateDefaultAction -SchemaVersion -AppNotificationMutableContent -UNNotificationTriggerType -ShouldUseRequestIdentifierForDismissalSync -TriggerRepeatInterval -SBSPushStoreNotificationThreadKey -AppNotificationAttachments -ToneFileName -Header -AppNotificationSummaryArgument -SBSPushStoreNotificationCategoryKey -AppNotificationTitle -' ' -$null \ No newline at end of file diff --git a/scripts/artifacts/accs.py b/scripts/artifacts/accs.py deleted file mode 100644 index f99e6edf..00000000 --- a/scripts/artifacts/accs.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import plistlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_accs(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(""" - select - datetime(zdate+978307200,'unixepoch','utc' ), - zaccounttypedescription, - zusername, - zaccountdescription, - zaccount.zidentifier, - zaccount.zowningbundleid - from zaccount, zaccounttype - where zaccounttype.z_pk=zaccount.zaccounttype - """ - ) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5])) - report = ArtifactHtmlReport('Account Data') - report.start_artifact_report(report_folder, 'Account Data') - report.add_script() - data_headers = ('Timestamp','Account Desc.','Username','Description','Identifier','Bundle ID' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Account Data' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Account Data' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc("No Account Data available") - - \ No newline at end of file diff --git a/scripts/artifacts/addressBook.py b/scripts/artifacts/addressBook.py deleted file mode 100644 index 8a31b89b..00000000 --- a/scripts/artifacts/addressBook.py +++ /dev/null @@ -1,57 +0,0 @@ -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_addressBook(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - ABPerson.ROWID, - c16Phone, - FIRST, - MIDDLE, - LAST, - c17Email, - DATETIME(CREATIONDATE+978307200,'UNIXEPOCH'), - DATETIME(MODIFICATIONDATE+978307200,'UNIXEPOCH'), - NAME - FROM ABPerson - LEFT OUTER JOIN ABStore ON ABPerson.STOREID = ABStore.ROWID - LEFT OUTER JOIN ABPersonFullTextSearch_content on ABPerson.ROWID = ABPersonFullTextSearch_content.ROWID - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - if row[1] is not None: - numbers = row[1].split(" +") - number = numbers[1].split(" ") - phone_number = "+{}".format(number[0]) - else: - phone_number = '' - - data_list.append((row[0], phone_number, row[2], row[3], row[4], row[5], row[6], row[7], row[8])) - - report = ArtifactHtmlReport('Address Book Contacts') - report.start_artifact_report(report_folder, 'Address Book Contacts') - report.add_script() - data_headers = ('Contact ID', 'Contact Number', 'First Name', 'Middle Name', 'Last Name', 'Email Address', 'Creation Date', 'Modification Date', 'Storage Place') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Address Book' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Address Book' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Address Book data available') - - db.close() - return diff --git a/scripts/artifacts/airtags.py b/scripts/artifacts/airtags.py deleted file mode 100644 index ceeed67c..00000000 --- a/scripts/artifacts/airtags.py +++ /dev/null @@ -1,200 +0,0 @@ -import os -import datetime -import json -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, logdevinfo, kmlgen - - -def timestampcalc(timevalue): - timestamp = (datetime.datetime.fromtimestamp(int(timevalue)/1000).strftime('%Y-%m-%d %H:%M:%S')) - return timestamp - -def get_airtags(files_found, report_folder, seeker): - data_list_info = [] - data_list_safeloc = [] - data_list_location = [] - data_list_crowdloc = [] - - for file_found in files_found: - file_found = str(file_found) - - with open(file_found, 'r') as f: - deserialized = json.load(f) - - for x in deserialized: - - name = (x['name']) - ptype = (x['productType'].get('type')) - maname = (x['productType']['productInformation'].get('manufacturerName')) - pid = (x['productType']['productInformation'].get('productIdentifier')) - vid = (x['productType']['productInformation'].get('vendorIdentifier')) - ap = (x['productType']['productInformation'].get('antennaPower')) - - gid = (x['groupIdentifier']) - - owner = (x.get('owner')) - batstat = (x['batteryStatus']) - - serial = (x['serialNumber']) - lostmode = (x['lostModeMetadata']) - - cap = (x['capabilities']) - id = (x['identifier']) - - asubAdministrativeArea = (x['address'].get('subAdministrativeArea')) - aslabel = (x['address'].get('label')) - astreetAddress = (x['address'].get('streetAddress')) - acountryCode = (x['address'].get('countryCode')) - astateCode = (x['address'].get('stateCode')) - administrativeArea = (x['address'].get('administrativeArea')) - astreetName = (x['address'].get('streetName')) - aformattedAddressLines = (x['address'].get('formattedAddressLines')) - amapItemFullAddress = (x['address'].get('mapItemFullAddress')) - afullThroroughfare = (x['address'].get('fullThroroughfare')) - areaOfInterest = (x['address'].get('areaOfInterest')) - alocality = (x['address'].get('locality')) - acountry = (x['address'].get('country')) - - lpostype = (x['location'].get('positionType')) - lverticalAccuracy = (x['location'].get('verticalAccuracy')) - llong = (x['location'].get('longitude')) - lfloor = (x['location'].get('floorLevel')) - lisin = (x['location'].get('isInaccurate')) - lisold = (x['location'].get('isOld')) - lhorz = (x['location'].get('horizontalAccuracy')) - llat = (x['location'].get('latitude')) - ltimestamp = (x['location'].get('timeStamp')) - ltimestamp = timestampcalc(ltimestamp) - lalt = (x['location'].get('altitude')) - lloc = (x['location'].get('locationFinished')) - - sysver = (x['systemVersion']) - crowdloc = (x['crowdSourcedLocation']) - crowdpostype = (x['crowdSourcedLocation'].get('positionType')) - crowdvert = (x['crowdSourcedLocation'].get('verticalAccuracy')) - crowdlong = (x['crowdSourcedLocation'].get('longitude')) - crowdfloor = (x['crowdSourcedLocation'].get('floorLevel')) - crowdisacc = (x['crowdSourcedLocation'].get('isInaccurate')) - crowdisold = (x['crowdSourcedLocation'].get('isOld')) - crowdhorzcc = (x['crowdSourcedLocation'].get('horizontalAccuracy')) - crowdlat = (x['crowdSourcedLocation'].get('latitude')) - crowdtimestamp= (x['crowdSourcedLocation'].get('timeStamp')) - crowdtimestamp = timestampcalc(crowdtimestamp) - crowdalt = (x['crowdSourcedLocation'].get('altitude')) - crowdlocfin = (x['crowdSourcedLocation'].get('locationFinished')) - - rname = (x['role'].get('name')) - remoji = (x['role'].get('emoji')) - ris = (x['role'].get('identifier')) - - for safeloc in x.get('safeLocations'): - sname = (safeloc.get('name')) - stype = (safeloc.get('type')) - sid = (safeloc.get('identifier')) - sva = (safeloc['location'].get('verticalAccuracy')) - sha = (safeloc['location'].get('horizontalAccuracy')) - slong = (safeloc['location'].get('longitude')) - slat = (safeloc['location'].get('latitude')) - sfloor = (safeloc['location'].get('floorLevel')) - sisina = (safeloc['location'].get('isInaccurate')) - sisold = (safeloc['location'].get('isOld')) - stimestamp = (safeloc['location'].get('timeStamp')) - stimestamp = timestampcalc(stimestamp) - salt = (safeloc['location'].get('altitude')) - ssub = (safeloc['address'].get('subAdministrativeArea')) - slabel = (safeloc['address'].get('label')) - sstreet = (safeloc['address'].get('streetAddres')) - scountry = (safeloc['address'].get('countryCode')) - sstate = (safeloc['address'].get('stateCode')) - sadmin = (safeloc['address'].get('administrativeArea')) - pstreetn = (safeloc['address'].get('streetName')) - sformated = (safeloc['address'].get('formattedAddressLines')) - smapfull = (safeloc['address'].get('mapItemFullAddress')) - sthro = (safeloc['address'].get('fullThroroughfare')) - saoi = (safeloc['address'].get('areaOfInterest')) - sloc = (safeloc['address'].get('locality')) - scount = (safeloc['address'].get('country')) - - data_list_safeloc.append((stimestamp, name, serial, id, rname, remoji, ris, sname, stype, sid, sva, sha, slong, slat, sfloor, sisina, sisold, salt, ssub, slabel, sstreet, scountry, sstate, sadmin, pstreetn, sformated, smapfull, sthro, saoi, sloc, scount)) - - data_list_info.append((name, serial, id, rname, remoji, ris, ptype, maname, pid, vid, ap, gid, owner, batstat, lostmode, cap, sysver,)) - - data_list_location.append((ltimestamp, name, serial, id, rname, remoji, ris, ptype, maname, pid, vid, ap, gid, owner, batstat, lostmode, cap, sysver, asubAdministrativeArea, aslabel, astreetAddress, acountryCode, astateCode, administrativeArea, astreetName, aformattedAddressLines, amapItemFullAddress, afullThroroughfare, areaOfInterest, alocality, lpostype, lverticalAccuracy, llong, lisin, lisold, lhorz, llat, lalt, lloc, acountry)) - - data_list_crowdloc.append((crowdtimestamp, name, serial, id, rname, remoji, ris, ptype, maname, pid, vid, ap, gid, owner, batstat, lostmode, cap, sysver, crowdpostype, crowdvert, crowdlong, crowdlat, crowdalt, crowdfloor, crowdisacc, crowdisold, crowdhorzcc, crowdlocfin )) - - if data_list_safeloc: - report = ArtifactHtmlReport('Safe Locations') - report.start_artifact_report(report_folder, 'Safe Locations') - report.add_script() - data_list_safeloc_headers = ('Timestamp', 'Name', 'Serial', 'ID', 'Role Name', 'Emoji', 'Role ID', 'Name', 'Type', 'Identifier', 'Vertical Accuracy', 'Horizontal Accuracy', 'Longitude', 'Latitude', 'Floor Level', 'Is Inaccurate', 'Is Old', 'Altitude', 'Sub-Administrative Area', 'Label', 'Street Address', 'Country Code', 'State Code', 'Administrative Area', 'Street Name', 'Formatted Address Line', 'Map Item Full Address', 'Throroughfare', 'Area of Interest', 'Locality', 'Country' ) - report.write_artifact_data_table(data_list_safeloc_headers, data_list_safeloc, file_found) - report.end_artifact_report() - - tsvname = f'Airtags Safe Locations' - tsv(report_folder, data_list_safeloc_headers, data_list_safeloc, tsvname) - - tlactivity = f'Airtags Safe Locations' - timeline(report_folder, tlactivity, data_list_safeloc, data_list_safeloc_headers) - - kmlactivity = 'Airtags Safe Locations' - kmlgen(report_folder, kmlactivity, data_list_safeloc, data_list_safeloc_headers) - else: - logfunc('No Airtags Safe Locations data available') - - if data_list_location: - report = ArtifactHtmlReport('Locations') - report.start_artifact_report(report_folder, 'Locations') - report.add_script() - data_list_location_headers = ('Timestamp','Name', 'Serial', 'ID', 'Role Name', 'Emoji', 'Role ID', 'Product Type', 'Manufacturer', 'Product ID', 'Vendor ID', 'Antenna Power', 'Group ID', 'Owner', 'Battery Status', 'Lost Mode', 'Capabilities', 'System Version', 'Sub-administrative Area', 'Label', 'Street Address', 'Country Code', 'State Code', 'Administrative Area', 'Street Name', 'Formatted Address Line', 'Item Full Address', 'Throroughfare', 'Area of Interest', 'Locality', 'Type', 'Vertical Accuracy', 'Longitude', 'Is Inaccurate', 'Is Old', 'Horizontal Accuracy', 'Latitude', 'Altitude', 'Location Finished', 'Country' ) - report.write_artifact_data_table(data_list_location_headers, data_list_location, file_found) - report.end_artifact_report() - - tsvname = f'Airtags Locations' - tsv(report_folder, data_list_location_headers, data_list_location, tsvname) - - tlactivity = f'Airtags Locations' - timeline(report_folder, tlactivity, data_list_location, data_list_location_headers) - - kmlactivity = 'Airtags Locations' - kmlgen(report_folder, kmlactivity, data_list_location, data_list_location_headers) - else: - logfunc('No Airtags Locations data available') - - if data_list_info: - report = ArtifactHtmlReport('Airtags Info') - report.start_artifact_report(report_folder, 'Airtags Info') - report.add_script() - data_list_info_headers = ('Name', 'Serial', 'ID', 'Role Name', 'Emoji', 'Role ID', 'Product Type', 'Manufacturer', 'Product ID', 'Vendor ID', 'Antenna Power', 'Group ID', 'Owner', 'Battery Status', 'Lost Mode', 'Capabilities', 'System Version' ) - report.write_artifact_data_table(data_list_info_headers, data_list_info, file_found) - report.end_artifact_report() - - tsvname = f'Airtags Info' - tsv(report_folder, data_list_info_headers, data_list_info, tsvname) - - tlactivity = f'Airtags Info' - timeline(report_folder, tlactivity, data_list_info, data_list_info_headers) - - else: - logfunc('No Airtags Info data available') - - - if data_list_crowdloc: - report = ArtifactHtmlReport('Crowdsourced Locations') - report.start_artifact_report(report_folder, 'Crowdsourced Locations') - report.add_script() - data_headers_crowdloc = ('Timestamp', 'Name', 'Serial', 'ID', 'Role Name', 'Emoji', 'Role ID', 'Product Type', 'Manufacturer', 'Product ID', 'Vendor ID', 'Antenna Power', 'Group ID', 'Owner', 'Battery Status', 'Lost Mode', 'Capabilities', 'System Version', 'Position Type', 'Vertical Accuracy', 'Longitude', 'Latitude', 'Altitude', 'Floor Level', 'Is Inaccurate', 'Is Old', 'Horizontal Accuracy', 'Location Finished') - report.write_artifact_data_table(data_headers_crowdloc, data_list_crowdloc, file_found) - report.end_artifact_report() - - tsvname = f'Airtgas Crowdsourced Locations' - tsv(report_folder, data_headers_crowdloc, data_list_crowdloc, tsvname) - - tlactivity = f'Airtags Crowdsourced Locations' - timeline(report_folder, tlactivity, data_list_crowdloc, data_headers_crowdloc) - - kmlactivity = 'Airtags Crowdsourced Locations' - kmlgen(report_folder, kmlactivity, data_list_crowdloc, data_headers_crowdloc) - - else: - logfunc('No Airtags Crowdsourced Locations data available') \ No newline at end of file diff --git a/scripts/artifacts/alarms.py b/scripts/artifacts/alarms.py deleted file mode 100644 index 8cecb79f..00000000 --- a/scripts/artifacts/alarms.py +++ /dev/null @@ -1,76 +0,0 @@ -import plistlib - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline - - -def get_alarms(files_found, report_folder, seeker): - data_list = [] - - for file_found in files_found: - with open(file_found, "rb") as plist_file: - pl = plistlib.load(plist_file) - - if 'MTAlarms' in pl: - if 'MTAlarms' in pl['MTAlarms']: - for alarms in pl['MTAlarms']['MTAlarms']: - alarms_dict = alarms['$MTAlarm'] - - alarm_title = alarms_dict.get('MTAlarmTitle', 'Alarm') - fire_date = alarms_dict.get('MTAlarmFireDate', '') - dismiss_date = alarms_dict.get('MTAlarmDismissDate', '') - repeat_schedule = decode_repeat_schedule(alarms_dict['MTAlarmRepeatSchedule']) - - data_list.append((alarm_title, alarms_dict['MTAlarmEnabled'], fire_date, dismiss_date, - alarms_dict['MTAlarmLastModifiedDate'], ', '.join(repeat_schedule), - alarms_dict['MTAlarmSound']['$MTSound']['MTSoundToneID'], - alarms_dict['MTAlarmIsSleep'], alarms_dict['MTAlarmBedtimeDoNotDisturb'], '')) - - if 'MTSleepAlarm' in pl['MTAlarms']: - for sleep_alarms in pl['MTAlarms']['MTSleepAlarm']: - sleep_alarm_dict = pl['MTAlarms']['MTSleepAlarm'][sleep_alarms] - - alarm_title = sleep_alarm_dict.get('MTAlarmTitle', 'Bedtime') - - repeat_schedule = decode_repeat_schedule(sleep_alarm_dict['MTAlarmRepeatSchedule']) - - data_list.append((alarm_title, sleep_alarm_dict['MTAlarmEnabled'], sleep_alarm_dict['MTAlarmFireDate'], - sleep_alarm_dict['MTAlarmDismissDate'], sleep_alarm_dict['MTAlarmLastModifiedDate'], - ', '.join(repeat_schedule), sleep_alarm_dict['MTAlarmSound']['$MTSound']['MTSoundToneID'], - sleep_alarm_dict['MTAlarmIsSleep'], sleep_alarm_dict['MTAlarmBedtimeDoNotDisturb'], - sleep_alarm_dict['MTAlarmBedtimeFireDate'])) - - if len(data_list) > 0: - report = ArtifactHtmlReport('Alarms') - report.start_artifact_report(report_folder, 'Alarms') - report.add_script() - data_headers = ('Alarm Title', 'Alarm Enabled', 'Fire Date', 'Dismiss Date', 'Last Modified', 'Repeat Schedule', 'Alarm Sound', 'Is Sleep Alarm', 'Bedtime Not Disturbed', 'Bedtime Fire Date') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Alarms' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Alarms' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Alarms found') - - -def decode_repeat_schedule(repeat_schedule_value): - days_list = {64: 'Sunday', 32: 'Saturday', 16: 'Friday', 8: 'Thursday', 4: 'Wednesday', 2: 'Tuesday', 1: 'Monday'} - schedule = [] - - if repeat_schedule_value == 127: - schedule.append('Every Day') - return schedule - elif repeat_schedule_value == 0: - schedule.append('Never') - return schedule - - for day in days_list: - if repeat_schedule_value > 0 and repeat_schedule_value >= day: - repeat_schedule_value -= day - schedule.append(days_list[day]) - return reversed(schedule) diff --git a/scripts/artifacts/appConduit.py b/scripts/artifacts/appConduit.py deleted file mode 100644 index d903ca9a..00000000 --- a/scripts/artifacts/appConduit.py +++ /dev/null @@ -1,84 +0,0 @@ -import datetime -import glob -import os -import sys -import stat -import pathlib -import string -import json -import re -import textwrap - -from html import escape - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - -def get_appConduit(files_found, report_folder, seeker): - data_list = [] - device_type_and_info = [] - - info = '' - reg_filter = (r'(([A-Za-z]+[\s]+([a-zA-Z]+[\s]+[0-9]+)[\s]+([0-9]+\:[0-9]+\:[0-9]+)[\s]+([0-9]{4}))([\s]+[\[\d\]]+[\s]+[\]+[\s]+[\(\w\)]+)[\s\-]+(((.*)(device+\:([\w]+\-[\w]+\-[\w]+\-[\w]+\-[\w]+))(.*)$)))') - date_filter = re.compile(reg_filter) - - source_files = [] - for file_found in files_found: - file_found = str(file_found) - if file_found.startswith('\\\\?\\'): - file_name = pathlib.Path(file_found[4:]).name - source_files.append(file_found[4:]) - else: - file_name = pathlib.Path(file_found).name - source_files.append(file_found) - - file = open(file_found, "r", encoding="utf8") - linecount = 0 - - for line in file: - linecount = linecount + 1 - line_match = re.match(date_filter, line) - - - if line_match: - date_time = line_match.group(3, 5, 4) - conv_time = ' '.join(date_time) - dtime_obj = datetime.datetime.strptime(conv_time, '%b %d %Y %H:%M:%S') - values = line_match.group(9) - device_id = line_match.group(11) - - if 'devicesAreNowConnected' in values: - device_type_and_info.append((device_id,line_match.group(12).split(" ")[4],line_match.group(12).split(" ")[5])) - info = 'Connected' - data_list.append((dtime_obj,info,device_id,file_name)) - if 'devicesAreNoLongerConnected' in values: - info = 'Disconnected' - data_list.append((dtime_obj,info,device_id,file_name)) - # if 'Resuming because' in values: - # info = 'Resumed' - # data_list.append((dtime_obj,info,device_id,device_type_tmp,file_name)) - # if 'Suspending because' in values: - # info = 'Suspended' - # data_list.append((dtime_obj,info,device_id,device_type_tmp,file_name)) - # if 'Starting reunion sync because device ' in values: - # info = 'Reachable again after reunion sync' - # data_list.append((dtime_obj,info,device_id,device_type_tmp,file_name)) - - device_type_and_info = list(set(device_type_and_info)) - - data_headers_device_info = ('Device ID', 'Device type and version', 'Device extra information') - data_headers = ('Time', 'Device interaction', 'Device ID', 'Log File Name') - - report = ArtifactHtmlReport('App Conduit') - report.start_artifact_report(report_folder, 'App Conduit', 'The AppConduit log file stores information about interactions between iPhone and other iOS devices, i.e. Apple Watch') - - report.add_script() - source_files_found = ', '.join(source_files) - - report.write_artifact_data_table(data_headers_device_info, device_type_and_info, source_files_found, cols_repeated_at_bottom=False) - report.write_artifact_data_table(data_headers, data_list, file_found, True, False) - report.end_artifact_report() - - tsvname = 'App Conduit' - tsv(report_folder, data_headers, data_list, tsvname) - \ No newline at end of file diff --git a/scripts/artifacts/appGrouplisting.py b/scripts/artifacts/appGrouplisting.py deleted file mode 100644 index 8bd5fd7b..00000000 --- a/scripts/artifacts/appGrouplisting.py +++ /dev/null @@ -1,43 +0,0 @@ -import biplist -import pathlib -import plistlib -import sys - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - - -def get_appGrouplisting(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - with open(file_found, "rb") as fp: - if sys.version_info >= (3, 9): - plist = plistlib.load(fp) - else: - plist = biplist.readPlist(fp) - bundleid = plist['MCMMetadataIdentifier'] - - p = pathlib.Path(file_found) - appgroupid = p.parent.name - fileloc = str(p.parents[1]) - typedir = str(p.parents[1].name) - - data_list.append((bundleid, typedir, appgroupid, fileloc)) - - if len(data_list) > 0: - filelocdesc = 'Path column in the report' - description = 'List can included once installed but not present apps. Each file is named .com.apple.mobile_container_manager.metadata.plist' - report = ArtifactHtmlReport('Bundle ID by AppGroup & PluginKit IDs') - report.start_artifact_report(report_folder, 'Bundle ID by AppGroup & PluginKit IDs', description) - report.add_script() - data_headers = ('Bundle ID','Type','Directory GUID','Path') - report.write_artifact_data_table(data_headers, data_list, filelocdesc) - report.end_artifact_report() - - tsvname = 'Bundle ID - AppGroup ID - PluginKit ID' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data on Bundle ID - AppGroup ID - PluginKit ID') - - \ No newline at end of file diff --git a/scripts/artifacts/appItunesmeta.py b/scripts/artifacts/appItunesmeta.py deleted file mode 100644 index a79cc8d7..00000000 --- a/scripts/artifacts/appItunesmeta.py +++ /dev/null @@ -1,68 +0,0 @@ -import biplist -import pathlib -import os -import nska_deserialize as nd -import plistlib -import sys - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - - -def get_appItunesmeta(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('iTunesMetadata.plist'): - with open(file_found, "rb") as fp: - if sys.version_info >= (3, 9): - plist = plistlib.load(fp) - else: - plist = biplist.readPlist(fp) - - purchasedate = plist.get('com.apple.iTunesStore.downloadInfo', {}).get('purchaseDate', '') - bundleid = plist.get('softwareVersionBundleId', '') - itemname = plist.get('itemName', '') - artistname = plist.get('artistName', '') - versionnum = plist.get('bundleShortVersionString', '') - downloadedby = plist.get('com.apple.iTunesStore.downloadInfo', {}) .get('accountInfo', {}).get('AppleID', '') - genre = plist.get('genre', '') - factoryinstall = plist.get('isFactoryInstall', '') - appreleasedate = plist.get('releaseDate', '') - sourceapp = plist.get('sourceApp', '') - sideloaded = plist.get('sideLoadedDeviceBasedVPP', '') - variantid = plist.get('variantID', '') - - p = pathlib.Path(file_found) - parent = p.parent - - itunes_metadata_path = (os.path.join(parent, "BundleMetadata.plist")) - if os.path.exists(itunes_metadata_path): - with open(itunes_metadata_path, 'rb') as f: - deserialized_plist = nd.deserialize_plist(f) - install_date = deserialized_plist.get('installDate', '') - else: - install_date = '' - - data_list.append((install_date, purchasedate, bundleid, itemname, artistname, versionnum, downloadedby, genre, factoryinstall, appreleasedate, sourceapp, sideloaded, variantid, parent)) - - if len(data_list) > 0: - fileloc = 'See source file location column' - description = 'iTunes & Bundle ID Metadata contents for apps' - report = ArtifactHtmlReport('Apps - Itunes & Bundle Metadata') - report.start_artifact_report(report_folder, 'Apps - Itunes Metadata', description) - report.add_script() - data_headers = ('Installed Date', 'App Purchase Date','Bundle ID', 'Item Name', 'Artist Name', 'Version Number', 'Downloaded by', 'Genre', 'Factory Install', 'App Release Date', 'Source App', 'Sideloaded?', 'Variant ID', 'Source File Location') - report.write_artifact_data_table(data_headers, data_list, fileloc) - report.end_artifact_report() - - tsvname = 'Apps - Itunes Bundle Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Apps - Itunes Bundle Metadata' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data on Apps - Itunes Bundle Metadata') - - \ No newline at end of file diff --git a/scripts/artifacts/appSnapshots.py b/scripts/artifacts/appSnapshots.py deleted file mode 100644 index fc3939f5..00000000 --- a/scripts/artifacts/appSnapshots.py +++ /dev/null @@ -1,93 +0,0 @@ -import datetime -import os -import shutil - -from html import escape -from PIL import Image -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows -from scripts.ktx.ios_ktx2png import KTX_reader, liblzfse -from urllib.parse import quote - -def save_ktx_to_png_if_valid(ktx_path, save_to_path): - '''Excludes all white or all black blank images''' - - with open(ktx_path, 'rb') as f: - ktx = KTX_reader() - try: - if ktx.validate_header(f): - data = ktx.get_uncompressed_texture_data(f) - dec_img = Image.frombytes('RGBA', (ktx.pixelWidth, ktx.pixelHeight), data, 'astc', (4, 4, False)) - # either all black or all white https://stackoverflow.com/questions/14041562/python-pil-detect-if-an-image-is-completely-black-or-white - # if sum(dec_img.convert("L").getextrema()) in (0, 2): - # logfunc('Skipping image as it is blank') - # return False - - dec_img.save(save_to_path, "PNG") - return True - except (OSError, ValueError, liblzfse.error) as ex: - logfunc(f'Had an exception - {str(ex)}') - return False - -def get_applicationSnapshots(files_found, report_folder, seeker): - - slash = '\\' if is_platform_windows() else '/' - data_headers = ('App Name', 'Source Path', 'Date Modified', 'Snapshot') - data_list = [] # Format= [ [ 'App Name', 'ktx_path', mod_date, 'png_path' ], .. ] - - for file_found in files_found: - file_found = str(file_found) - if os.path.isdir(file_found): - continue - if file_found.lower().endswith('.ktx'): - if os.path.getsize(file_found) < 2500: # too small, they are blank - continue - parts = file_found.split(slash) - if parts[-2] != 'downscaled': - app_name = parts[-2].split(' ')[0] - else: - app_name = parts[-3].split(' ')[0] - - png_path = os.path.join(report_folder, app_name + '_' + parts[-1][:-4] + '.png') - if save_ktx_to_png_if_valid(file_found, png_path): - last_modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(file_found)) - data_list.append([app_name, file_found, last_modified_date, png_path]) - - elif file_found.lower().endswith('.jpeg'): - parts = file_found.split(slash) - if parts[-2] != 'downscaled': - app_name = parts[-2].split(' ')[0] - else: - app_name = parts[-3].split(' ')[0] - if app_name.startswith('sceneID'): - app_name = app_name[8:] - #if app_name.endswith('-default'): - # app_name = app_name[:-8] - dash_pos = app_name.find('-') - if dash_pos > 0: - app_name = app_name[0:dash_pos] - - jpg_path = os.path.join(report_folder, app_name + '_' + parts[-1]) - if shutil.copy2(file_found, jpg_path): - last_modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(file_found)) - data_list.append([app_name, file_found, last_modified_date, jpg_path]) - - if len(data_list): - description = "Snapshots saved by iOS for individual apps appear here. Blank screenshots are excluded here. Dates and times shown are from file modified timestamps" - report = ArtifactHtmlReport('App Snapshots (screenshots)') - report.start_artifact_report(report_folder, 'App Snapshots', description) - report.add_script() - report_folder_name = os.path.basename(report_folder.rstrip(slash)) - data_list_for_report = [] - for app_name, ktx_path, mod_date, png_path in data_list: - dir_path, base_name = os.path.split(png_path) - img_html = ''.format(quote(base_name), quote(report_folder_name)) - data_list_for_report.append( (escape(app_name), escape(ktx_path), mod_date, img_html) ) - report.write_artifact_data_table(data_headers, data_list_for_report, '', html_escape=False, write_location=False) - report.end_artifact_report() - - tsvname = 'App Snapshots' - tsv_headers = ('App Name', 'Source Path', 'Date Modified') - tsv(report_folder, tsv_headers, data_list, tsvname) - else: - logfunc('No snapshots available') \ No newline at end of file diff --git a/scripts/artifacts/appleMapsApplication.py b/scripts/artifacts/appleMapsApplication.py deleted file mode 100644 index 72b70da8..00000000 --- a/scripts/artifacts/appleMapsApplication.py +++ /dev/null @@ -1,38 +0,0 @@ -import plistlib -import blackboxprotobuf -import scripts.artifacts.artGlobals - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - - -def get_appleMapsApplication(files_found, report_folder, seeker): - versionnum = 0 - file_found = str(files_found[0]) - - with open(file_found, 'rb') as f: - plist = plistlib.load(f) - - types = {'1': {'type': 'double', 'name': 'Latitude'}, - '2': {'type': 'double', 'name': 'Longitude'}, - '3': {'type': 'double', 'name': ''}, - '4': {'type': 'fixed64', 'name': ''}, - '5': {'type': 'double', 'name': ''} - } - protobuf = plist.get('__internal__LastActivityCamera', None) - if protobuf: - internal_plist, di = blackboxprotobuf.decode_message(protobuf,types) - latitude = (internal_plist['Latitude']) - longitude = (internal_plist['Longitude']) - - data_list = [] - data_list.append((latitude, longitude)) - report = ArtifactHtmlReport('Apple Maps App') - report.start_artifact_report(report_folder, 'Apple Maps App') - report.add_script() - data_headers = ('Latitude','Longitude' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Apple Maps Application' - tsv(report_folder, data_headers, data_list, tsvname) \ No newline at end of file diff --git a/scripts/artifacts/appleMapsGroup.py b/scripts/artifacts/appleMapsGroup.py deleted file mode 100644 index cb8d3e08..00000000 --- a/scripts/artifacts/appleMapsGroup.py +++ /dev/null @@ -1,49 +0,0 @@ -import plistlib -import blackboxprotobuf -import scripts.artifacts.artGlobals - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - - -def get_appleMapsGroup(files_found, report_folder, seeker): - versionnum = 0 - file_found = str(files_found[0]) - - with open(file_found, 'rb') as f: - deserialized_plist = plistlib.load(f) - types = {'1': {'type': 'message', 'message_typedef': - {'1': {'type': 'int', 'name': ''}, - '2': {'type': 'int', 'name': ''}, - '5': {'type': 'message', 'message_typedef': - {'1': {'type': 'double', 'name': 'Latitude'}, - '2': {'type': 'double', 'name': 'Longitude'}, - '3': {'type': 'double', 'name': ''}, - '4': {'type': 'fixed64', 'name': ''}, - '5': {'type': 'double', 'name': ''}}, - 'name': ''}, - '7': {'type': 'int', 'name': ''}}, - 'name': ''} - } - try: - internal_deserialized_plist, di = blackboxprotobuf.decode_message((deserialized_plist['MapsActivity']),types) - - latitude =(internal_deserialized_plist['1']['5']['Latitude']) - longitude =(internal_deserialized_plist['1']['5']['Longitude']) - - data_list = [] - data_list.append((latitude, longitude)) - report = ArtifactHtmlReport('Apple Maps Group') - report.start_artifact_report(report_folder, 'Apple Maps Group') - report.add_script() - data_headers = ('Latitude','Longitude' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Apple Maps Group' - tsv(report_folder, data_headers, data_list, tsvname) - except: - logfunc('No data in Apple Maps Group') - - - \ No newline at end of file diff --git a/scripts/artifacts/appleMapsSearchHistory.py b/scripts/artifacts/appleMapsSearchHistory.py deleted file mode 100644 index b12c3696..00000000 --- a/scripts/artifacts/appleMapsSearchHistory.py +++ /dev/null @@ -1,46 +0,0 @@ -import plistlib - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - - -def get_appleMapsSearchHistory(files_found, report_folder, seeker): - data_list = [] - - for file_found in files_found: - file_found = str(file_found) - with open(file_found, "rb") as plist_file: - plist_content = plistlib.load(plist_file) - for entry in plist_content['MSPHistory']['records']: - search_history = plist_content['MSPHistory']['records'][entry] - content = search_history.get('contents') - if content: - content = content.decode('UTF-8', 'ignore') - else: - content = None - timestamp = search_history.get('modificationDate') - formatted_timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%S') - if content: - if len(content) < 300: - id_search_entry = content.split('\n') - search_entry = id_search_entry[1].split('"') - search_entry_split = str(search_entry[0]).split('\x12') - search_entry_filtered = list(filter(None, search_entry_split)) - data_list.append((formatted_timestamp, ', '.join(search_entry_filtered))) - - if len(data_list) > 0: - report = ArtifactHtmlReport('Apple Maps Search History') - report.start_artifact_report(report_folder, 'Apple Maps Search History') - report.add_script() - data_headers = ("Timestamp", "Search Entry") - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Apple Maps Search History' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Apple Maps Search History' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No data available for Apple Maps Search History') diff --git a/scripts/artifacts/applePodcasts.py b/scripts/artifacts/applePodcasts.py deleted file mode 100644 index be8d9287..00000000 --- a/scripts/artifacts/applePodcasts.py +++ /dev/null @@ -1,98 +0,0 @@ -import sqlite3 -import textwrap - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, get_next_unused_name, open_sqlite_db_readonly - -def get_applePodcasts(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - if not file_found.endswith('.sqlite'): - continue # Skip all other files - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - datetime(ZADDEDDATE + 978307200, 'unixepoch'), - datetime(ZLASTDATEPLAYED + 978307200, 'unixepoch'), - datetime(ZUPDATEDDATE + 978307200, 'unixepoch'), - datetime(ZDOWNLOADEDDATE + 978307200, 'unixepoch'), - ZAUTHOR, - ZTITLE, - ZFEEDURL, - ZITEMDESCRIPTION, - ZWEBPAGEURL - from ZMTPODCAST - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Apple Podcasts - Shows') - report.start_artifact_report(report_folder, 'Apple Podcasts - Shows') - report.add_script() - data_headers = ('Date Added','Date Last Played','Date Last Updated','Date Downloaded','Author','Title','Feed URL','Description','Web Page URL') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Apple Podcasts - Shows' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Apple Podcasts - Shows' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Apple Podcasts - Shows data available') - - cursor.execute(''' - SELECT - datetime(ZIMPORTDATE + 978307200, 'unixepoch'), - CASE ZMETADATATIMESTAMP - WHEN 0 THEN '' - ELSE datetime(ZMETADATATIMESTAMP + 978307200, 'unixepoch') - END, - datetime(ZLASTDATEPLAYED + 978307200, 'unixepoch'), - datetime(ZPLAYSTATELASTMODIFIEDDATE + 978307200, 'unixepoch'), - datetime(ZDOWNLOADDATE + 978307200, 'unixepoch'), - ZPLAYCOUNT, - ZAUTHOR, - ZTITLE, - ZITUNESSUBTITLE, - ZASSETURL, - ZWEBPAGEURL, - ZDURATION, - ZBYTESIZE, - ZPLAYSTATE - FROM ZMTEPISODE - ORDER by ZMETADATATIMESTAMP - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - report = ArtifactHtmlReport('Apple Podcasts - Episodes') - report.start_artifact_report(report_folder, 'Apple Podcasts - Episodes') - report.add_script() - data_headers = ('Import Date','Metadata Timestamp','Date Last Played','Play State Last Modified','Download Date','Play Count','Author','Title','Subtitle','Asset URL','Web Page URL','Duration','Size','Play State') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8],row[9],row[10],row[11],row[12],row[13])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Apple Podcasts - Episodes' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Apple Podcasts - Episodes' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Apple Podcasts - Episodes data available') - - db.close() - return diff --git a/scripts/artifacts/appleWalletCards.py b/scripts/artifacts/appleWalletCards.py deleted file mode 100644 index bddb0e0a..00000000 --- a/scripts/artifacts/appleWalletCards.py +++ /dev/null @@ -1,78 +0,0 @@ -import re - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_appleWalletCards(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.db'): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute('''SELECT - TIME_STAMP, - PROTO_PROPS - FROM CFURL_CACHE_RESPONSE - INNER JOIN CFURL_CACHE_BLOB_DATA ON CFURL_CACHE_BLOB_DATA.ENTRY_ID = CFURL_CACHE_RESPONSE.ENTRY_ID - WHERE REQUEST_KEY LIKE '%CARDS' - ''') - - all_rows = cursor.fetchall() - db_file = file_found - - if len(all_rows) > 0: - for row in all_rows: - card_info = str(row[1], 'utf-8', 'ignore') - card_number = get_bank_card_number(card_info) - expiration_date = re.findall(r'\d{2}/\d{2}', card_info) - card_type = get_card_type(card_number, len(card_number)) - - data_list.append((row[0], card_number, expiration_date[0], card_type)) - - report = ArtifactHtmlReport('Cards') - report.start_artifact_report(report_folder, 'Cards') - report.add_script() - data_headers = ('Timestamp (Card Added)', 'Card Number', 'Expiration Date', 'Type') - report.write_artifact_data_table(data_headers, data_list, db_file) - report.end_artifact_report() - - tsvname = 'Apple Wallet Cards' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Apple Wallet Cards' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Apple Wallet Cards available') - - db.close() - return - - -def get_bank_card_number(card_information): - num_of_digits = [19, 18, 17, 16, 15, 14, 13] - - for digit_num in num_of_digits: - found_entry = re.findall(r'\d{{{digits}}}'.format(digits=digit_num), card_information) - if found_entry: - return found_entry[0] - - -def get_card_type(card_num, num_length): - first_digit = str(card_num)[:1] - first_two_digits = str(card_num)[:2] - - if first_digit == '4' and (num_length == 13 or num_length == 16): - return 'Visa' - elif first_digit == '5' and num_length == 16: - return 'Mastercard' - elif first_digit == '6' and num_length == 16: - return 'Discover' - elif (first_two_digits == '34' or first_two_digits == '37') and num_length == 15: - return 'American Express' - elif (first_two_digits == '30' or first_two_digits == '36' or first_two_digits == '38') and num_length == 14: - return 'Diners Club Carte Blanche' - else: - return 'Unknown' diff --git a/scripts/artifacts/appleWalletPasses.py b/scripts/artifacts/appleWalletPasses.py deleted file mode 100644 index b01ad644..00000000 --- a/scripts/artifacts/appleWalletPasses.py +++ /dev/null @@ -1,69 +0,0 @@ -import shutil -import json -from os import listdir -from re import search, DOTALL -from os.path import isfile, join, basename, dirname - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_appleWalletPasses(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('json'): - unique_id = search(r'(?<=ards/)(.*?)(?=.pkpass)', dirname(file_found), flags=DOTALL).group(0) - filename = '{}_{}'.format(unique_id, basename(file_found)) - shutil.copyfile(file_found, join(report_folder, filename)) - - json_files = [join(report_folder, file) for file in listdir(report_folder) if isfile(join(report_folder, file))] - - if file_found.endswith('.sqlite3'): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute('''SELECT UNIQUE_ID, ORGANIZATION_NAME, TYPE_ID, LOCALIZED_DESCRIPTION, - DATETIME(INGESTED_DATE + 978307200,'UNIXEPOCH'), DELETE_PENDING, ENCODED_PASS, - FRONT_FIELD_BUCKETS, BACK_FIELD_BUCKETS - FROM PASS - ''') - - all_rows = cursor.fetchall() - db_file = file_found - - if len(all_rows) > 0: - for row in all_rows: - for json_file in json_files: - if row[0] in basename(json_file): - - # noinspection PyBroadException - try: - with open(json_file) as json_content: - json_data = json.load(json_content) - except Exception: - json_data = 'Malformed data' - - encoded_pass = str(row[6], 'utf-8', 'ignore') - front_field = str(row[7], 'utf-8', 'ignore') - back_field = str(row[8], 'utf-8', 'ignore') - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], json_data, front_field, back_field, encoded_pass)) - - report = ArtifactHtmlReport('Passes') - report.start_artifact_report(report_folder, 'Passes') - report.add_script() - data_headers = ('Unique ID', 'Organization Name', 'Type', 'Localized Description', 'Pass Added', - 'Pending Delete', 'Pass Details', 'Front Fields Content', 'Back Fields Content', 'Encoded Pass') - report.write_artifact_data_table(data_headers, data_list, db_file) - report.end_artifact_report() - - tsvname = 'Apple Wallet Passes' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Apple Wallet Passes' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Apple Wallet Passes available') - - db.close() - return diff --git a/scripts/artifacts/appleWalletTransactions.py b/scripts/artifacts/appleWalletTransactions.py deleted file mode 100644 index 534bb24c..00000000 --- a/scripts/artifacts/appleWalletTransactions.py +++ /dev/null @@ -1,50 +0,0 @@ -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_appleWalletTransactions(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute('''SELECT - DATETIME(TRANSACTION_DATE + 978307200,'UNIXEPOCH'), - MERCHANT_NAME, - LOCALITY, - ADMINISTRATIVE_AREA, - CAST(AMOUNT AS REAL)/100, - CURRENCY_CODE, - DATETIME(LOCATION_DATE + 978307200,'UNIXEPOCH'), - LOCATION_LATITUDE, - LOCATION_LONGITUDE, - LOCATION_ALTITUDE, - PEER_PAYMENT_COUNTERPART_HANDLE, - PEER_PAYMENT_MEMO, - TRANSACTION_STATUS, - TRANSACTION_TYPE - FROM PAYMENT_TRANSACTION - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13])) - - report = ArtifactHtmlReport('Transactions') - report.start_artifact_report(report_folder, 'Transactions') - report.add_script() - data_headers = ('Transaction Date', 'Merchant', 'Locality', 'Administrative Area', 'Currency Amount', 'Currency Type', 'Location Date', 'Latitude', 'Longitude', 'Altitude', 'Peer Payment Handle', 'Payment Memo', 'Transaction Status', 'Transaction Type') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Apple Wallet Transactions' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Apple Wallet Transactions' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Apple Wallet Transactions available') - - db.close() - return diff --git a/scripts/artifacts/appleWifiPlist.py b/scripts/artifacts/appleWifiPlist.py deleted file mode 100644 index 3b848787..00000000 --- a/scripts/artifacts/appleWifiPlist.py +++ /dev/null @@ -1,265 +0,0 @@ -import glob -import plistlib -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows - -def hexify_byte(byte_to_convert): - to_return = hex(byte_to_convert).replace('0x','') - if len(to_return) < 2: - to_return = "0" + to_return - - return to_return - -def _bytes_to_mac_address(encoded_bytes): - to_return = '' - to_return = hexify_byte(encoded_bytes[0]) + ":" + hexify_byte(encoded_bytes[1]) + ":" - to_return = to_return + hexify_byte(encoded_bytes[2]) + ":" + hexify_byte(encoded_bytes[3]) + ":" - to_return = to_return + hexify_byte(encoded_bytes[4]) + ":" + hexify_byte(encoded_bytes[5]) - - return to_return - -def get_appleWifiPlist(files_found, report_folder, seeker): - known_data_list = [] - scanned_data_list = [] - known_files = [] - scanned_files = [] - for file_found in files_found: - file_found = str(file_found) - - with open(file_found, 'rb') as f: - deserialized = plistlib.load(f) - if 'KeepWiFiPoweredAirplaneMode' in deserialized: - val = (deserialized['KeepWiFiPoweredAirplaneMode']) - logdevinfo(f"Keep Wifi Powered Airplane Mode: {val}") - - if 'List of known networks' in deserialized: - known_files.append(file_found) - for known_network in deserialized['List of known networks']: - ssid = '' - bssid = '' - last_updated = '' - last_auto_joined = '' - wnpmd = '' - net_usage = '' - country_code = '' - device_name = '' - manufacturer = '' - serial_number = '' - model_name = '' - enabled = '' - last_joined = '' - add_reason = '' - carplay = '' - bundle = '' - system_joined = '' - user_joined = '' - - if 'SSID_STR' in known_network: - ssid = str(known_network['SSID_STR']) - - if 'BSSID' in known_network: - bssid = str(known_network['BSSID']) - - if 'networkUsage' in known_network: - net_usage = str(known_network['networkUsage']) - - if '80211D_IE' in known_network: - if 'IE_KEY_80211D_COUNTRY_CODE' in known_network['80211D_IE']: - country_code = str(known_network['80211D_IE']['IE_KEY_80211D_COUNTRY_CODE']) - - if 'lastUpdated' in known_network: - last_updated = str(known_network['lastUpdated']) - - if 'lastAutoJoined' in known_network: - last_auto_joined = str(known_network['lastAutoJoined']) - - if 'lastJoined' in known_network: - last_joined = str(known_network['lastJoined']) - - if 'WiFiNetworkPasswordModificationDate' in known_network: - wnpmd = str(known_network['WiFiNetworkPasswordModificationDate']) - - if 'enabled' in known_network: - enabled = str(known_network['enabled']) - - if 'WPS_PROB_RESP_IE' in known_network: - - if 'IE_KEY_WPS_DEV_NAME' in known_network['WPS_PROB_RESP_IE']: - device_name = known_network['WPS_PROB_RESP_IE']['IE_KEY_WPS_DEV_NAME'] - if 'IE_KEY_WPS_MANUFACTURER' in known_network['WPS_PROB_RESP_IE']: - manufacturer = known_network['WPS_PROB_RESP_IE']['IE_KEY_WPS_MANUFACTURER'] - if 'IE_KEY_WPS_SERIAL_NUM' in known_network['WPS_PROB_RESP_IE']: - serial_number = known_network['WPS_PROB_RESP_IE']['IE_KEY_WPS_SERIAL_NUM'] - if 'IE_KEY_WPS_MODEL_NAME' in known_network['WPS_PROB_RESP_IE']: - model_name = known_network['WPS_PROB_RESP_IE']['IE_KEY_WPS_MODEL_NAME'] - - if 'CARPLAY_NETWORK' in known_network: - carplay = str(known_network['CARPLAY_NETWORK']) - - known_data_list.append([ssid, - bssid, - net_usage, - country_code, - device_name, - manufacturer, - serial_number, - model_name, - last_joined, - last_auto_joined, - system_joined, - user_joined, - last_updated, - enabled, - wnpmd, - carplay, - add_reason, - bundle, - file_found]) - - if 'com.apple.wifi.known-networks.plist' in file_found: - known_files.append(file_found) - for network_key in deserialized: - known_network = deserialized[network_key] - ssid = '' - bssid = '' - last_updated = '' - last_auto_joined = '' - wnpmd = '' - net_usage = '' - country_code = '' - device_name = '' - manufacturer = '' - serial_number = '' - model_name = '' - enabled = '' - last_joined = '' - add_reason = '' - bundle = '' - system_joined = '' - user_joined = '' - - if 'SSID' in known_network: - ssid = str(known_network['SSID']) - - if 'AddReason' in known_network: - add_reason = str(known_network['AddReason']) - - if 'UpdatedAt' in known_network: - last_updated = str(known_network['UpdatedAt']) - - if 'JoinedBySystemAt' in known_network: - system_joined = str(known_network['JoinedBySystemAt']) - - if 'JoinedByUserAt' in known_network: - user_joined = str(known_network['JoinedByUserAt']) - - if 'BundleID' in known_network: - bundle = str(known_network['BundleID']) - - if '__OSSpecific__' in known_network: - - if 'BSSID' in known_network['__OSSpecific__']: - bssid = str(known_network['__OSSpecific__']['BSSID']) - - if 'networkUsage' in known_network['__OSSpecific__']: - net_usage = str(known_network['__OSSpecific__']['networkUsage']) - - if 'WiFiNetworkPasswordModificationDate' in known_network['__OSSpecific__']: - wnpmd = str(known_network['__OSSpecific__']['WiFiNetworkPasswordModificationDate']) - - if 'CARPLAY_NETWORK' in known_network['__OSSpecific__']: - carplay = str(known_network['__OSSpecific__']['CARPLAY_NETWORK']) - - known_data_list.append([ssid, - bssid, - net_usage, - country_code, - device_name, - manufacturer, - serial_number, - model_name, - last_joined, - last_auto_joined, - system_joined, - user_joined, - last_updated, - enabled, - wnpmd, - carplay, - add_reason, - bundle, - file_found]) - - if 'List of scanned networks with private mac' in deserialized: - scanned_files.append(file_found) - for scanned_network in deserialized['List of scanned networks with private mac']: - ssid = '' - bssid = '' - last_updated = '' - last_joined = '' - private_mac_in_use = '' - private_mac_value = '' - private_mac_valid = '' - added_at = '' - in_known_networks = '' - - if 'SSID_STR' in scanned_network: - ssid = str(scanned_network['SSID_STR']) - - if 'BSSID' in scanned_network: - bssid = str(scanned_network['BSSID']) - - if 'lastUpdated' in scanned_network: - last_updated = str(scanned_network['lastUpdated']) - - if 'lastJoined' in scanned_network: - last_joined = str(scanned_network['lastJoined']) - - if 'addedAt' in scanned_network: - added_at = str(scanned_network['addedAt']) - - if 'PresentInKnownNetworks' in scanned_network: - in_known_networks = str(scanned_network['PresentInKnownNetworks']) - - if 'PRIVATE_MAC_ADDRESS' in scanned_network: - if 'PRIVATE_MAC_ADDRESS_IN_USE' in scanned_network['PRIVATE_MAC_ADDRESS']: - private_mac_in_use = str(_bytes_to_mac_address(scanned_network['PRIVATE_MAC_ADDRESS']['PRIVATE_MAC_ADDRESS_IN_USE'])) - if 'PRIVATE_MAC_ADDRESS_VALUE' in scanned_network['PRIVATE_MAC_ADDRESS']: - private_mac_value = str(_bytes_to_mac_address(scanned_network['PRIVATE_MAC_ADDRESS']['PRIVATE_MAC_ADDRESS_VALUE'])) - if 'PRIVATE_MAC_ADDRESS_VALID' in scanned_network['PRIVATE_MAC_ADDRESS']: - private_mac_valid = str(scanned_network['PRIVATE_MAC_ADDRESS']['PRIVATE_MAC_ADDRESS_VALID']) - - scanned_data_list.append([ssid, bssid, added_at, last_joined, last_updated, private_mac_in_use, private_mac_value, private_mac_valid, in_known_networks, file_found]) - - if len(known_data_list) > 0: - description = 'WiFi known networks data. Dates are taken straight from the source plist.' - report = ArtifactHtmlReport('Locations') - report.start_artifact_report(report_folder, 'WiFi Known Networks', description) - report.add_script() - data_headers = ['SSID','BSSID','Network Usage','Country Code','Device Name','Manufacturer','Serial Number','Model Name','Last Joined','Last Auto Joined','System Joined','User Joined','Last Updated','Enabled','WiFi Network Password Modification Date','Carplay Network','Add Reason','Bundle ID','File'] - report.write_artifact_data_table(data_headers, known_data_list, ', '.join(known_files)) - report.end_artifact_report() - - tsvname = 'WiFi Known Networks' - tsv(report_folder, data_headers, known_data_list, tsvname) - - tlactivity = 'WiFi Known Networks' - timeline(report_folder, tlactivity, known_data_list, data_headers) - - if len(scanned_data_list) > 0: - description = 'WiFi networks scanned while using fake ("private") MAC address. Dates are taken straight from the source plist.' - report = ArtifactHtmlReport('Locations') - report.start_artifact_report(report_folder, 'WiFi Networks Scanned (private)', description) - report.add_script() - data_headers = ['SSID','BSSID','Added At','Last Joined','Last Updated','MAC Used For Network','Private MAC Computed For Network','MAC Valid','In Known Networks','File'] - report.write_artifact_data_table(data_headers, scanned_data_list, ', '.join(scanned_files)) - report.end_artifact_report() - - tsvname = 'WiFi Networks Scanned (private)' - tsv(report_folder, data_headers, scanned_data_list, tsvname) - - tlactivity = 'WiFi Networks Scanned (private)' - timeline(report_folder, tlactivity, scanned_data_list, data_headers) diff --git a/scripts/artifacts/applicationstate.py b/scripts/artifacts/applicationstate.py deleted file mode 100644 index a7291d7f..00000000 --- a/scripts/artifacts/applicationstate.py +++ /dev/null @@ -1,73 +0,0 @@ -import biplist -import io -import nska_deserialize as nd -import plistlib -import sqlite3 -import sys - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows, open_sqlite_db_readonly - -def get_applicationstate(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select ait.application_identifier as ai, kvs.value as compat_info, - (SELECT kvs.value from kvs left join application_identifier_tab on application_identifier_tab.id = kvs.application_identifier - left join key_tab on kvs.key = key_tab.id - WHERE key_tab.key='XBApplicationSnapshotManifest' and kvs.key = key_tab.id - and application_identifier_tab.id = ait.id - ) as snap_info - from kvs - left join application_identifier_tab ait on ait.id = kvs.application_identifier - left join key_tab on kvs.key = key_tab.id - where key_tab.key='compatibilityInfo' - order by ait.id - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - snap_info_list = [] - for row in all_rows: - bundleid = str(row[0]) - plist_file_object = io.BytesIO(row[1]) - if row[1].find(b'NSKeyedArchiver') == -1: - if sys.version_info >= (3, 9): - plist = plistlib.load(plist_file_object) - else: - plist = biplist.readPlist(plist_file_object) - else: - try: - plist = nd.deserialize_plist(plist_file_object) - except (nd.DeserializeError, nd.biplist.NotBinaryPlistException, nd.biplist.InvalidPlistException, - nd.plistlib.InvalidFileException, nd.ccl_bplist.BplistError, ValueError, TypeError, OSError, OverflowError) as ex: - logfunc(f'Failed to read plist for {row[0]}, error was:' + str(ex)) - if plist: - if type(plist) is dict: - var1 = plist.get('bundleIdentifier', '') - var2 = plist.get('bundlePath', '') - var3 = plist.get('sandboxPath', '') - data_list.append((var1, var2, var3)) - if row[2]: - snap_info_list.append((var1, var2, var3, row[2])) - else: - logfunc(f'For {row[0]} Unexpected type "' + str(type(plist)) + '" found as plist root, can\'t process') - else: - logfunc(f'For {row[0]}, plist could not be read!') - report = ArtifactHtmlReport('Application State') - report.start_artifact_report(report_folder, 'Application State DB') - report.add_script() - data_headers = ('Bundle ID','Bundle Path','Sandbox Path') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Application State' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No Application State data available') - - db.close() - return \ No newline at end of file diff --git a/scripts/artifacts/artGlobals.py b/scripts/artifacts/artGlobals.py index 3b176f92..f6731ba6 100644 --- a/scripts/artifacts/artGlobals.py +++ b/scripts/artifacts/artGlobals.py @@ -1 +1 @@ -versionf = '0' \ No newline at end of file +versionf = '0' diff --git a/scripts/artifacts/bluetooth.py b/scripts/artifacts/bluetooth.py deleted file mode 100644 index ecb6c409..00000000 --- a/scripts/artifacts/bluetooth.py +++ /dev/null @@ -1,142 +0,0 @@ -import plistlib -import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def get_bluetooth(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - if file_found.endswith('com.apple.MobileBluetooth.ledevices.other.db'): # regex '**/Library/Database/com.apple.MobileBluetooth.ledevices.other.db' - get_bluetoothOther(file_found, report_folder, seeker) - elif file_found.endswith('com.apple.MobileBluetooth.ledevices.paired.db'): # regex '**/com.apple.MobileBluetooth.ledevices.paired.db' - get_bluetoothPaired(file_found, report_folder, seeker) - elif file_found.endswith('com.apple.MobileBluetooth.devices.plist'): # regex '**/com.apple.MobileBluetooth.devices.plist' - get_bluetoothPairedReg(file_found, report_folder, seeker) - -def get_bluetoothOther(file_found, report_folder, seeker): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute( - """ - SELECT - Name, - Address, - LastSeenTime, - Uuid - FROM - OtherDevices - order by Name desc - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[3])) - - description = '' - report = ArtifactHtmlReport('Bluetooth Other LE') - report.start_artifact_report(report_folder, 'Other LE', description) - report.add_script() - data_headers = ('Name','Address','UUID') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Bluetooth Other LE' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available for Bluetooth Other') - - db.close() - -def get_bluetoothPaired(file_found, report_folder, seeker): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - select - Uuid, - Name, - NameOrigin, - Address, - ResolvedAddress, - LastSeenTime, - LastConnectionTime - from - PairedDevices - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4],row[6])) - - description = '' - report = ArtifactHtmlReport('Bluetooth Paired LE') - report.start_artifact_report(report_folder, 'Paired LE', description) - report.add_script() - data_headers = ('UUID','Name','Name Origin','Address','Resolved Address','Last Connection Time') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Bluetooth Paired LE' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available for Bluetooth Paired LE') - - db.close() - -def get_bluetoothPairedReg(file_found, report_folder, seeker): - data_list = [] - with open(file_found, 'rb') as f: - plist = plistlib.load(f) - #print(plist) - if len(plist) > 0: - for x in plist.items(): - macaddress = x[0] - #print(x[1]) - if 'LastSeenTime' in x[1]: - lastseen = x[1]['LastSeenTime'] - lastseen = (datetime.datetime.fromtimestamp(int(lastseen)).strftime('%Y-%m-%d %H:%M:%S')) - else: - lastseen = '' - if 'UserNameKey' in x[1]: - usernkey = x[1]['UserNameKey'] - else: - usernkey = '' - - if 'Name' in x[1]: - nameu = x[1]['Name'] - else: - nameu = '' - if 'DeviceIdProduct' in x[1]: - deviceid = x[1]['DeviceIdProduct'] - else: - deviceid = '' - if 'DefaultName' in x[1]: - defname = x[1]['DefaultName'] - else: - defname = '' - - data_list.append((lastseen, macaddress, usernkey, nameu, deviceid, defname)) - - description = '' - report = ArtifactHtmlReport('Bluetooth Paired') - report.start_artifact_report(report_folder, 'Paired', description) - report.add_script() - data_headers = ('Last Seen Time','MAC Address','Name Key','Name','Device Product ID','Default Name' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Bluetooth Paired' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Bluetooth Paired' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Bluetooth paired devices') \ No newline at end of file diff --git a/scripts/artifacts/cacheRoutesGmap.py b/scripts/artifacts/cacheRoutesGmap.py deleted file mode 100644 index e5c567bf..00000000 --- a/scripts/artifacts/cacheRoutesGmap.py +++ /dev/null @@ -1,45 +0,0 @@ -import glob -import plistlib -import os -import datetime -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, kmlgen, timeline, tsv, is_platform_windows - - -def get_cacheRoutesGmap(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - filename = os.path.basename(file_found) - noext = os.path.splitext(filename)[0] - noext = int(noext) - datetime_time = datetime.datetime.fromtimestamp(noext/1000) - datetime_time = str(datetime_time) - with open(file_found, 'rb') as f: - deserialized = plistlib.load(f) - length = len(deserialized['$objects']) - for x in range(length): - try: - lat = deserialized['$objects'][x]['_coordinateLat'] - lon = deserialized['$objects'][x]['_coordinateLong'] #lat longs - data_list.append((datetime_time, lat, lon, file_found)) - except: - pass - - if len(data_list) > 0: - description = 'Google Maps Cache Routes' - report = ArtifactHtmlReport('Locations') - report.start_artifact_report(report_folder, 'Google Maps Cache Routes', description) - report.add_script() - data_headers = ('Timestamp','Latitude','Longitude','Source File') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Google Maps Cache Routes' - tsv(report_folder, data_headers, data_list, tsvname) - - kmlactivity = 'Google Maps Cache Routes' - kmlgen(report_folder, kmlactivity, data_list, data_headers) \ No newline at end of file diff --git a/scripts/artifacts/calendarAll.py b/scripts/artifacts/calendarAll.py deleted file mode 100644 index 3018c1d4..00000000 --- a/scripts/artifacts/calendarAll.py +++ /dev/null @@ -1,117 +0,0 @@ -import glob -import os -import sys -import stat -import pathlib -import plistlib -import sqlite3 -import json - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_calendarAll(files_found, report_folder, seeker): - file_found = str(files_found[0]) - #os.chmod(file_found, 0o0777) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute( - """ - select - title, - flags, - color, - symbolic_color_name, - external_id, - self_identity_email - from Calendar - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5])) - - description = '' - report = ArtifactHtmlReport('Calendar List') - report.start_artifact_report(report_folder, 'List', description) - report.add_script() - data_headers = ('Title','Flags','Color','Symbolic Color Name','External ID','Self Identity Email') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Calendar List ' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available for Calendar List') - - cursor.execute( - """ - Select - DATETIME(start_date + 978307200, 'UNIXEPOCH') as startdate, - start_tz, - DATETIME(end_date + 978307200, 'UNIXEPOCH') as enddate, - end_tz, - all_day, - summary, - calendar_id, - DATETIME(last_modified+ 978307200, 'UNIXEPOCH') as lastmod - from CalendarItem - order by startdate - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7])) - - description = '' - report = ArtifactHtmlReport('Calendar Items') - report.start_artifact_report(report_folder, 'Items', description) - report.add_script() - data_headers = ('Start Date','Start Timezone','End Date','End Timezone','All Day?','Summary','Calendar ID','Last Modified') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Calendar Items' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Calendar Items' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data available for Calendar Items') - - cursor.execute( - """ - SELECT - display_name, - address, - first_name, - last_name - from Identity - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3])) - - description = '' - report = ArtifactHtmlReport('Calendar Identity') - report.start_artifact_report(report_folder, 'Identity', description) - report.add_script() - data_headers = ('Display Name','Address','First Name','Last Name') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Calendar Identity' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available for Calendar Identity') \ No newline at end of file diff --git a/scripts/artifacts/callHistory.py b/scripts/artifacts/callHistory.py deleted file mode 100644 index 5306e1cd..00000000 --- a/scripts/artifacts/callHistory.py +++ /dev/null @@ -1,70 +0,0 @@ -import sqlite3 -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def get_callHistory(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.storedata'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - datetime(ZDATE+978307200,'unixepoch'), - ZADDRESS, - ZNAME, - case ZANSWERED - when 0 then 'No' - when 1 then 'Yes' - end, - case ZCALLTYPE - when 0 then 'Third-Party App' - when 1 then 'Phone' - when 8 then 'FaceTime Video' - when 16 then 'FaceTime Audio' - else ZCALLTYPE - end, - case ZORIGINATED - when 0 then 'Incoming' - when 1 then 'Outgoing' - end, - strftime('%H:%M:%S',ZDURATION, 'unixepoch'), - upper(ZISO_COUNTRY_CODE), - ZLOCATION, - ZSERVICE_PROVIDER - from ZCALLRECORD - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - - for row in all_rows: - an = str(row[1]) - an = an.replace("b'", "") - an = an.replace("'", "") - data_list.append((row[0], an, row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9])) - - report = ArtifactHtmlReport('Call History') - report.start_artifact_report(report_folder, 'Call History') - report.add_script() - data_headers = ('Timestamp', 'Phone Number', 'Name', 'Answered', 'Call Type', 'Call Direction', 'Call Duration', 'ISO Country Code', 'Location', 'Service Provider') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Call History' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Call History' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Call History data available') - - db.close() - return diff --git a/scripts/artifacts/cashApp.py b/scripts/artifacts/cashApp.py deleted file mode 100644 index 6b650b34..00000000 --- a/scripts/artifacts/cashApp.py +++ /dev/null @@ -1,77 +0,0 @@ -import re - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_cashApp(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - db = open_sqlite_db_readonly(file_found) - db.text_factory = lambda b: b.decode(errors = 'ignore') - cursor = db.cursor() - cursor.execute('''SELECT - --- Description of the role of the user account signed into the CashApp application of the device. -CASE WHEN ZPAYMENT.ZSYNCPAYMENT LIKE '%"RECIPIENT"%' THEN 'RECIPIENT' ELSE 'SENDER' END AS "Account Owner Role", - ---Full name of the customer as entered into the "First Name" and "Last Name" fields upon application setup. -LTRIM(SUBSTR(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), INSTR(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), CAST(',"full_name":' AS BLOB)), -instr(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), CAST('","is_cash' AS BLOB)) - -instr(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), CAST(',"full_name":' AS BLOB))), ',"full_name":"') AS 'CUSTOMER FULL DISPLAY NAME', - ---Customer's username created upon application setup. -CASE WHEN INSTR(ZSYNCCUSTOMER, '"cashtag":null') THEN '***NO CASH TAG***' WHEN ZSYNCCUSTOMER LIKE '%C_INCOMING_TRANSFER%' THEN '***NO CASH TAG***' ELSE -LTRIM(SUBSTR(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), INSTR(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), CAST(',"cashtag":' AS BLOB)), -instr(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), CAST('","is_verification' AS BLOB)) - -instr(CAST(ZCUSTOMER.ZSYNCCUSTOMER AS BLOB), CAST(',"cashtag":' AS BLOB))), ',"cashtag":"') END CASHTAG, - ---Transaction amount sent/received between the account user and customer -printf("$%.2f", LTRIM( SUBSTR(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), INSTR(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), CAST('{"amount":' AS BLOB)), -instr(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), CAST(',"currency' AS BLOB)) - -instr(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), CAST('ount":' AS BLOB)) - 6), '{"amount":') / 100.0) AS 'Transaction Amount', - ---Note provided by the sender. Like a memo line on a bank check. -CASE WHEN ZPAYMENT.ZSYNCPAYMENT LIKE '%"note"%' THEN LTRIM( SUBSTR(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), INSTR(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), CAST(',"note":' AS BLOB)), -instr(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), CAST(',"sent' AS BLOB)) - -instr(CAST(ZPAYMENT.ZSYNCPAYMENT AS BLOB), CAST('"note":' AS BLOB))), ',"note":') ELSE '***NO NOTE PRESENT***' END NOTE, - ---State of the transaction. Certain times the user may have to accept or decline a payment or payment request from the sender. -CASE WHEN ZPAYMENT.ZSYNCPAYMENT LIKE '%"COMPLETED"%' THEN 'COMPLETED' WHEN ZPAYMENT.ZSYNCPAYMENT LIKE '%"CANCELED"%' THEN 'CANCELED' ELSE 'WAITING ON RECIPIENT' END AS 'Transaction State', - ---Unix Epoch timestamp for the transaction display time. -datetime(ZPAYMENT.ZDISPLAYDATE/1000.0,'unixepoch') as "TRANSACTION DISPLAY DATE" - -FROM ZPAYMENT -INNER JOIN ZCUSTOMER ON ZCUSTOMER.ZCUSTOMERTOKEN = ZPAYMENT.ZREMOTECUSTOMERID -ORDER BY ZPAYMENT.ZDISPLAYDATE ASC - ''') - - all_rows = cursor.fetchall() - db_file = file_found - - if len(all_rows) > 0: - - data_list = [] - for row in all_rows: - data_list.append((row[6], row[1], row[2], row[0], row[3], row[5], row[4])) - - report = ArtifactHtmlReport('Transactions') - report.start_artifact_report(report_folder, 'Transactions') - report.add_script() - data_headers = ('Transaction Date', 'Display Name', 'Cashtag', 'Account Owner Role', 'Currency Amount', 'Transaction State', 'Transaction State') - report.write_artifact_data_table(data_headers, data_list, db_file) - report.end_artifact_report() - - tsvname = 'Cash App Transactions' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Cash App Transactions' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Cash App Transactions available') - - db.close() - return diff --git a/scripts/artifacts/celWireless.py b/scripts/artifacts/celWireless.py deleted file mode 100644 index e62a746d..00000000 --- a/scripts/artifacts/celWireless.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import plistlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - -def get_celWireless(files_found, report_folder, seeker): - data_list = [] - for filepath in files_found: - basename = os.path.basename(filepath) - if ( - basename == "com.apple.commcenter.device_specific_nobackup.plist" - or basename == "com.apple.commcenter.plist" - ): - p = open(filepath, "rb") - plist = plistlib.load(p) - for key, val in plist.items(): - data_list.append((key, val, filepath)) - if key == "ReportedPhoneNumber": - logdevinfo(f"Reported Phone Number: {val}") - - if key == "CDMANetworkPhoneNumberICCID": - logdevinfo(f"CDMA Network Phone Number ICCID: {val}") - - if key == "imei": - logdevinfo(f"IMEI: {val}") - - if key == "LastKnownICCID": - logdevinfo(f"Last Known ICCID: {val}") - - if key == "meid": - logdevinfo(f"MEID: {val}") - - - - location = 'see source field' - report = ArtifactHtmlReport('Cellular Wireless') - report.start_artifact_report(report_folder, 'Cellular Wireless') - report.add_script() - data_headers = ('Key','Values', 'Source' ) - report.write_artifact_data_table(data_headers, data_list, location) - report.end_artifact_report() - - tsvname = 'Cellular Wireless' - tsv(report_folder, data_headers, data_list, tsvname) - diff --git a/scripts/artifacts/cloudkitParticipants.py b/scripts/artifacts/cloudkitParticipants.py deleted file mode 100644 index 89db4a88..00000000 --- a/scripts/artifacts/cloudkitParticipants.py +++ /dev/null @@ -1,74 +0,0 @@ -import glob -import os -import nska_deserialize as nd -import sqlite3 -import datetime -import io - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_cloudkitParticipants(files_found, report_folder, seeker): - - user_dictionary = {} - - for file_found in files_found: - file_found = str(file_found) - - # Can add a separate section for each file this information is found in. - # This is for Apple Notes. - if file_found.endswith('NoteStore.sqlite'): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT Z_PK, ZSERVERSHAREDATA - FROM - ZICCLOUDSYNCINGOBJECT - WHERE - ZSERVERSHAREDATA NOT NULL - ''') - - all_rows = cursor.fetchall() - for row in all_rows: - - filename = os.path.join(report_folder, 'zserversharedata_'+str(row[0])+'.bplist') - output_file = open(filename, "wb") - output_file.write(row[1]) - output_file.close() - - deserialized_plist = nd.deserialize_plist(io.BytesIO(row[1])) - for item in deserialized_plist: - if 'Participants' in item: - for participant in item['Participants']: - record_id = participant['UserIdentity']['UserRecordID']['RecordName'] - email_address = participant['UserIdentity']['LookupInfo']['EmailAddress'] - phone_number = participant['UserIdentity']['LookupInfo']['PhoneNumber'] - first_name = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.givenName'] - middle_name = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.middleName'] - last_name = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.familyName'] - name_prefix = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.namePrefix'] - name_suffix = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.nameSuffix'] - nickname = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.nickname'] - - user_dictionary[record_id] = [record_id, email_address, phone_number, name_prefix, first_name, middle_name, last_name, name_suffix, nickname] - db.close() - - # Build the array after dealing with all the files - user_list = list(user_dictionary.values()) - - if len(user_list) > 0: - description = 'CloudKit Participants - Cloudkit accounts participating in CloudKit shares.' - report = ArtifactHtmlReport('Participants') - report.start_artifact_report(report_folder, 'Participants', description) - report.add_script() - user_headers = ('Record ID','Email Address','Phone Number','Name Prefix','First Name','Middle Name','Last Name','Name Suffix','Nickname') - report.write_artifact_data_table(user_headers, user_list, '', write_location=False) - report.end_artifact_report() - - tsvname = 'Cloudkit Participants' - tsv(report_folder, user_headers, user_list, tsvname) - else: - logfunc('No Cloudkit - Cloudkit Participants data available') - - diff --git a/scripts/artifacts/cloudkitSharing.py b/scripts/artifacts/cloudkitSharing.py deleted file mode 100644 index 279600bc..00000000 --- a/scripts/artifacts/cloudkitSharing.py +++ /dev/null @@ -1,136 +0,0 @@ -import glob -import os -import nska_deserialize as nd -import sqlite3 -import datetime -import io - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def get_cloudkitSharing(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('NoteStore.sqlite'): - get_cloudkitServerRecordData(file_found, report_folder, seeker) - get_cloudkitServerSharedData(file_found, report_folder, seeker) - -def get_cloudkitServerSharedData(file_found, report_folder, seeker): - user_dictionary = {} - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT Z_PK, ZSERVERSHAREDATA - FROM - ZICCLOUDSYNCINGOBJECT - WHERE - ZSERVERSHAREDATA NOT NULL - ''') - - all_rows = cursor.fetchall() - for row in all_rows: - - filename = os.path.join(report_folder, 'zserversharedata_'+str(row[0])+'.bplist') - output_file = open(filename, "wb") - output_file.write(row[1]) - output_file.close() - - deserialized_plist = nd.deserialize_plist(io.BytesIO(row[1])) - for item in deserialized_plist: - if 'Participants' in item: - for participant in item['Participants']: - record_id = participant['UserIdentity']['UserRecordID']['RecordName'] - email_address = participant['UserIdentity']['LookupInfo']['EmailAddress'] - phone_number = participant['UserIdentity']['LookupInfo']['PhoneNumber'] - first_name = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.givenName'] - middle_name = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.middleName'] - last_name = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.familyName'] - name_prefix = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.namePrefix'] - name_suffix = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.nameSuffix'] - nickname = participant['UserIdentity']['NameComponents']['NS.nameComponentsPrivate']['NS.nickname'] - - user_dictionary[record_id] = [record_id, email_address, phone_number, name_prefix, first_name, middle_name, last_name, name_suffix, nickname] - db.close() - - # Build the array after dealing with all the files - user_list = list(user_dictionary.values()) - - if len(user_list) > 0: - description = 'CloudKit Participants - Cloudkit accounts participating in CloudKit shares.' - report = ArtifactHtmlReport('Participants') - report.start_artifact_report(report_folder, 'Participants', description) - report.add_script() - user_headers = ('Record ID','Email Address','Phone Number','Name Prefix','First Name','Middle Name','Last Name','Name Suffix','Nickname') - report.write_artifact_data_table(user_headers, user_list, '', write_location=False) - report.end_artifact_report() - - tsvname = 'Cloudkit Participants' - tsv(report_folder, user_headers, user_list, tsvname) - else: - logfunc('No Cloudkit - Cloudkit Participants data available') - -def get_cloudkitServerRecordData(file_found, report_folder, seeker): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select z_pk, zserverrecorddata - from - ziccloudsyncingobject - where - zserverrecorddata not null - ''') - - note_data = [] - all_rows = cursor.fetchall() - result_number = len(all_rows) - if result_number > 0: - - for row in all_rows: - - filename = os.path.join(report_folder, 'zserverrecorddata_'+str(row[0])+'.bplist') - output_file = open(filename, "wb") - output_file.write(row[1]) - output_file.close() - - deserialized_plist = nd.deserialize_plist(io.BytesIO(row[1])) - creator_id = '' - last_modified_id = '' - creation_date = '' - last_modified_date = '' - last_modified_device = '' - record_type = '' - record_id = '' - for item in deserialized_plist: - if 'RecordCtime' in item: - creation_date = item['RecordCtime'] - elif 'RecordMtime' in item: - last_modified_date = item['RecordMtime'] - elif 'LastModifiedUserRecordID' in item: - last_modified_id = item['LastModifiedUserRecordID']['RecordName'] - elif 'CreatorUserRecordID' in item: - creator_id = item['CreatorUserRecordID']['RecordName'] - elif 'ModifiedByDevice' in item: - last_modified_device = item['ModifiedByDevice'] - elif 'RecordType' in item: - record_type = item['RecordType'] - elif 'RecordID' in item: - record_id = item['RecordID']['RecordName'] - - note_data.append([record_id,record_type,creation_date,creator_id,last_modified_date,last_modified_id,last_modified_device]) - - description = 'CloudKit Note Sharing - Notes information shared via CloudKit. Look up the Record ID in the ZICCLOUDSYYNCINGOBJECT.ZIDENTIFIER column. ' - report = ArtifactHtmlReport('Note Sharing') - report.start_artifact_report(report_folder, 'Note Sharing', description) - report.add_script() - note_headers = ('Record ID','Record Type','Creation Date','Creator ID','Modified Date','Modifier ID','Modifier Device') - report.write_artifact_data_table(note_headers, note_data, file_found) - report.end_artifact_report() - - tsvname = 'Cloudkit Note Sharing' - tsv(report_folder, note_headers, note_data, tsvname) - else: - logfunc('No Cloudkit - Cloudkit Note Sharing data available') - - db.close() diff --git a/scripts/artifacts/conDev.py b/scripts/artifacts/conDev.py deleted file mode 100644 index a4aa5c5a..00000000 --- a/scripts/artifacts/conDev.py +++ /dev/null @@ -1,62 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - -def get_conDev(files_found, report_folder, seeker): - file_found = str(files_found[0]) - with open(file_found, "rb") as f: - data = f.read() - userComps = "" - - logfunc("Data being interpreted for FRPD is of type: " + str(type(data))) - x = type(data) - byteArr = bytearray(data) - userByteArr = bytearray() - - magicOffset = byteArr.find(b"\x01\x01\x80\x00\x00") - magic = byteArr[magicOffset : magicOffset + 5] - - flag = 0 - - if magic == b"\x01\x01\x80\x00\x00": - logfunc( - "Found magic bytes in iTunes Prefs FRPD... Finding Usernames and Desktop names now" - ) - for x in range(int(magicOffset + 92), len(data)): - if (data[x]) == 0: - x = int(magicOffset) + 157 - if userByteArr.decode() == "": - continue - else: - if flag == 0: - userComps += userByteArr.decode() + " - " - flag = 1 - else: - userComps += userByteArr.decode() + "\n" - flag = 0 - userByteArr = bytearray() - continue - else: - char = data[x] - userByteArr.append(char) - - report = ArtifactHtmlReport('Connected Devices') - report.start_artifact_report(report_folder, 'Connected Devices') - report.add_script() - data_list = [] - data_list.append((userComps,)) - data_headers = ('User & Computer Names', ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Connected Devices' - tsv(report_folder, data_headers, data_list, tsvname) - - return - - diff --git a/scripts/artifacts/confaccts.py b/scripts/artifacts/confaccts.py deleted file mode 100644 index 9e69ec8f..00000000 --- a/scripts/artifacts/confaccts.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import plistlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - - -def get_confaccts(files_found, report_folder, seeker): - data_list = [] - file_found = str(files_found[0]) - with open(file_found, "rb") as fp: - pl = plistlib.load(fp) - for key, val in pl.items(): - data_list.append((key, val)) - - report = ArtifactHtmlReport('Account Configuration') - report.start_artifact_report(report_folder, 'Account Configuration') - report.add_script() - data_headers = ('Key','Values' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Account Configuration' - tsv(report_folder, data_headers, data_list, tsvname) - - diff --git a/scripts/artifacts/deviceActivator.py b/scripts/artifacts/deviceActivator.py deleted file mode 100644 index 7c08cee7..00000000 --- a/scripts/artifacts/deviceActivator.py +++ /dev/null @@ -1,64 +0,0 @@ -import re -import base64 -import os -from itertools import compress -import xml.etree.ElementTree as ET - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, logdevinfo, is_platform_windows - -def get_deviceActivator(files_found, report_folder, seeker): - data_list = [] - alllines = '' - file_found = str(files_found[0]) - - with open(file_found, 'r') as f_in: - for line in f_in: - line = line.strip() - alllines = alllines + line - - found = re.findall('ActivationInfoXML(.*)RKCertification', alllines) - base64_message= found[0] - - data = base64.b64decode(base64_message) - - outpath = os.path.join(report_folder, "results.xml") - with open(outpath, 'wb') as f_out: - f_out.write(data) - - xmlfile = outpath - tree = ET.parse(xmlfile) - root = tree.getroot() - - for elem in root: - for elemx in elem: - for elemz in elemx: - data_list.append(str(elemz.text).strip()) - - it = iter(data_list) - results = list(zip(it, it)) - - for x in results: - if x[0] == 'EthernetMacAddress': - logdevinfo(f"Ethernet Mac Address: {x[1]}") - if x[0] == 'BluetoothAddress': - logdevinfo(f"Bluetooth Address: {x[1]}") - if x[0] == 'WifiAddress': - logdevinfo(f"Wifi Address: {x[1]}") - if x[0] == 'ModelNumber': - logdevinfo(f"Model Number: {x[1]}") - - if len(results) > 0: - report = ArtifactHtmlReport('iOS Device Activator Data') - report.start_artifact_report(report_folder, 'iOS Device Activator Data') - report.add_script() - data_headers = ('Key','Values') - report.write_artifact_data_table(data_headers, results, file_found) - report.end_artifact_report() - - tsvname = 'iOS Device Activator Data' - tsv(report_folder, data_headers, results, tsvname) - else: - logfunc('No iOS Device Activator Data') - - \ No newline at end of file diff --git a/scripts/artifacts/dhcphp.py b/scripts/artifacts/dhcphp.py deleted file mode 100644 index 3d82336f..00000000 --- a/scripts/artifacts/dhcphp.py +++ /dev/null @@ -1,45 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - -def get_dhcphp(files_found, report_folder, seeker): - file_found = str(files_found[0]) - data_list = [] - reportval = '' - with open(file_found, "r") as filefrom: - for line in filefrom: - cline = line.strip() - if cline == "{": - reportval = reportval + ("") - elif cline == "}": - reportval = reportval +("
KeyValues
") - data_list.append((reportval,)) - reportval = '' - # elif cline == '': - # f.write('
') - else: - ll = cline.split("=") - reportval = reportval +(f"{ll[0]}") - reportval = reportval +(f"{ll[1]}") - - - - if len(data_list) > 0: - report = ArtifactHtmlReport('DHCP Hotspot Clients') - report.start_artifact_report(report_folder, 'Hotspot Clients') - report.add_script() - data_headers = ('Hotspot Clients',) - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - tsvname = 'DHCP Hotspot Clients' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available') - return \ No newline at end of file diff --git a/scripts/artifacts/dhcpl.py b/scripts/artifacts/dhcpl.py deleted file mode 100644 index 8275ae72..00000000 --- a/scripts/artifacts/dhcpl.py +++ /dev/null @@ -1,42 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - -def get_dhcpl(files_found, report_folder, seeker): - file_found = str(files_found[0]) - data_list = [] - with open(file_found, "rb") as fp: - pl = plistlib.load(fp) - for key, val in pl.items(): - if key == "IPAddress": - data_list.append((key,val)) - if key == "LeaseLength": - data_list.append((key,val)) - if key == "LeaseStartDate": - data_list.append((key,val)) - if key == "RouterHardwareAddress": - data_list.append((key,val)) - if key == "RouterIPAddress": - data_list.append((key,val)) - if key == "SSID": - data_list.append((key,val)) - - if len(data_list) > 0: - report = ArtifactHtmlReport('DHCP Received List') - report.start_artifact_report(report_folder, 'Received List') - report.add_script() - data_headers = ('Key', 'Value') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'DHCP Received List' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available') - return \ No newline at end of file diff --git a/scripts/artifacts/discordAcct.py b/scripts/artifacts/discordAcct.py deleted file mode 100644 index 01079f1c..00000000 --- a/scripts/artifacts/discordAcct.py +++ /dev/null @@ -1,68 +0,0 @@ -import gzip -import re -import os -import json -import shutil -import errno -from pathlib import Path -import string -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows - -def strings(filename, min=4): - with open(filename, errors="ignore") as f: # Python 3.x - # with open(filename, "rb") as f: # Python 2.x - result = "" - for c in f.read(): - if c in string.printable: - result += c - continue - if len(result) >= min: - yield result - result = "" - if len(result) >= min: # catch result at EOF - yield result - -def get_discordAcct(files_found, report_folder, seeker): - searchlist = [] - for file_found in files_found: - file_found = str(file_found) - - for s in strings(file_found): - #print(type(s)) - #print(s) - searchlist.append(str(s),) - - counter = 0 - data_list = [] - for x in searchlist: - counter += 1 - if 'user_id_cache' in x: - #print(x) - wf = searchlist[counter].split('"') - try: - data_list.append(('USER_ID_CACHE', wf[1])) - except: - pass - - if 'email_cache' in x: - #print(x) - wfa = searchlist[counter].split('"') - try: - data_list.append(('EMAIL_CACHE', wfa[1])) - except: - pass - - if len(data_list) > 0: - report = ArtifactHtmlReport('Discord Account') - report.start_artifact_report(report_folder, 'Discord Account') - report.add_script() - data_headers = ('Key', 'Value') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Discord Account' - tsv(report_folder, data_headers, data_list, tsvname) diff --git a/scripts/artifacts/discordJson.py b/scripts/artifacts/discordJson.py deleted file mode 100644 index b88527e9..00000000 --- a/scripts/artifacts/discordJson.py +++ /dev/null @@ -1,136 +0,0 @@ -import gzip -import re -import os -import json -import shutil -import errno -from pathlib import Path -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows - - -def get_discordJson(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - #logfunc(file_found) - pathed = file_found - - try: - if os.path.isfile(file_found): - with open(file_found) as f_in: - for jsondata in f_in: - #jsondata = jsondata[1:-1] - jsonfinal = json.loads(jsondata) - #print (jsonfinal) - - x = 0 - emdeddedauthor = '' - authorurl = '' - authoriconurl = '' - embededurl = '' - embededurl = '' - embededdescript = '' - footertext = '' - footericonurl = '' - - listlength = len(jsonfinal) - if isinstance(jsonfinal, list): - while x < listlength: - - if 'author' in jsonfinal[x]: - username = (jsonfinal[x]['author']['username']) - userid = (jsonfinal[x]['author']['id']) - if 'bot' in jsonfinal[x]['author']: - botuser = (jsonfinal[x]['author']['bot']) - else: - botuser = '' - - if 'timestamp' in jsonfinal[x]: - timestamp = (jsonfinal[x]['timestamp']) - - if 'edited_timestamp' in jsonfinal[x]: - editedtimestamp = (jsonfinal[x]['edited_timestamp']) - - if 'content' in jsonfinal[x]: - content = jsonfinal[x]['content'] - - if 'channel_id' in jsonfinal[x]: - channelid = jsonfinal[x]['channel_id'] - - - if 'attachments' in jsonfinal[x]: - attachments = jsonfinal[x]['attachments'] - - if len(attachments) > 0: - string = (attachments[0]['url']) - attachments = string - else: - attachments = '' - - if 'embeds' in jsonfinal[x]: - if len(jsonfinal[x]['embeds']) > 0: - y = 0 - lenembeds = (len(jsonfinal[x]['embeds'])) - while y < lenembeds: - #print(jsonfinal[x]['embeds']) - if 'url' in jsonfinal[x]['embeds'][y]: - embededurl = (jsonfinal[x]['embeds'][y]['url']) - else: - embededurl = '' - - if 'description' in jsonfinal[x]['embeds'][y]: - embededdescript = (jsonfinal[x]['embeds'][y]['description']) - else: - embededdescript = '' - - if 'author' in jsonfinal[x]['embeds'][y]: - emdeddedauthor = (jsonfinal[x]['embeds'][y]['author']['name']) - if 'url' in jsonfinal[x]['embeds'][y]['author']: - authorurl = (jsonfinal[x]['embeds'][y]['author']['url']) - else: - authorurl = '' - if 'icon_url' in jsonfinal[x]['embeds'][y]['author']: - authoriconurl =(jsonfinal[x]['embeds'][y]['author']['icon_url']) - else: - authoriconurl = '' - else: - emdeddedauthor = '' - - if 'footer' in jsonfinal[x]['embeds']: - footertext = (jsonfinal[x]['embeds'][y]['footer']['text']) - footericonurl = (jsonfinal[x]['embeds'][y]['footer']['icon_url']) - else: - footertext = '' - footericonurl = '' - - y = y + 1 - - pathedhead, pathedtail = os.path.split(pathed) - data_list.append((timestamp, editedtimestamp, username, botuser, content, attachments, userid, channelid, emdeddedauthor, authorurl, authoriconurl, embededurl, embededdescript, footertext, footericonurl, pathedtail)) - - x = x + 1 - else: - pass - #logfunc('JSON data is no expected list') - except ValueError as e: - pass - #logfunc('JSON error: %s' % e) - #logfunc('') - if len(data_list) > 0: - logfunc(f'Files found:{len(files_found)}') - report = ArtifactHtmlReport('Discord Messages') - report.start_artifact_report(report_folder, 'Discord Messages') - report.add_script() - data_headers = ('Timestamp','Edited Timestamp','Username','Bot?','Content','Attachments','User ID','Channel ID','Embedded Author','Author URL','Author Icon URL','Embedded URL','Embedded Script','Footer Text', 'Footer Icon URL', 'Source File') - report.write_artifact_data_table(data_headers, data_list, pathedhead) - report.end_artifact_report() - - tsvname = 'Discord Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Discord Messages' - timeline(report_folder, tlactivity, data_list, data_headers) \ No newline at end of file diff --git a/scripts/artifacts/discordManifest.py b/scripts/artifacts/discordManifest.py deleted file mode 100644 index 4da4215d..00000000 --- a/scripts/artifacts/discordManifest.py +++ /dev/null @@ -1,36 +0,0 @@ - -import os -import json -from pathlib import Path -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows - - -def get_discordManifest(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - - if os.path.isfile(file_found): - with open(file_found) as f_in: - for jsondata in f_in: - jsonfinal = json.loads(jsondata) - - for key, value in jsonfinal.items(): - data_list.append((key, value)) - - - if len(data_list) > 0: - report = ArtifactHtmlReport('Discord Manifest') - report.start_artifact_report(report_folder, 'Discord Manifest') - report.add_script() - data_headers = ('Key', 'Value') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Discord Manifest' - tsv(report_folder, data_headers, data_list, tsvname) - \ No newline at end of file diff --git a/scripts/artifacts/filesAppsclient.py b/scripts/artifacts/filesAppsclient.py deleted file mode 100644 index ca8e2dd0..00000000 --- a/scripts/artifacts/filesAppsclient.py +++ /dev/null @@ -1,53 +0,0 @@ -import glob -import os -import nska_deserialize as nd -import sqlite3 -import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_filesAppsclient(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('client.db'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - item_birthtime, - item_filename, - version_mtime - FROM - client_items - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - birthtime = datetime.datetime.fromtimestamp(row[0]) - versionmtime = datetime.datetime.fromtimestamp(row[2]) - data_list.append((birthtime, row[1], versionmtime)) - - description = ' Items stored in iCloud Drive with metadata about files. ' - report = ArtifactHtmlReport('Files App - iCloud Client Items') - report.start_artifact_report(report_folder, 'Files App - iCloud Client Items', description) - report.add_script() - data_headers = ('Birthtime', 'Filename', 'Version Modified Time' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Files App - iCloud Client Items' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Files App - iCloud Client Items' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Files App - iCloud Client Items data available') - diff --git a/scripts/artifacts/filesAppsdb.py b/scripts/artifacts/filesAppsdb.py deleted file mode 100644 index f38453ac..00000000 --- a/scripts/artifacts/filesAppsdb.py +++ /dev/null @@ -1,82 +0,0 @@ -import glob -import os -import nska_deserialize as nd -import sqlite3 -import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_filesAppsdb(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('server.db'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT * - FROM - DEVICES - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - - for row in all_rows: - data_list.append((row[1],)) - - description = 'Device names that are able to sync to iCloud Drive.' - report = ArtifactHtmlReport('Files App - iCloud Sync Names') - report.start_artifact_report(report_folder, 'Files App - iCloud Sync Names', description) - report.add_script() - data_headers = ('Name', ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Files App - iCloud Sync Names' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('No Files App - iCloud Sync Names data available') - - - cursor.execute(''' - SELECT - item_birthtime, - item_filename, - version_mtime - FROM - server_items - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - birthtime = datetime.datetime.fromtimestamp(row[0]) - versionmtime = datetime.datetime.fromtimestamp(row[2]) - data_list.append((birthtime, row[1], versionmtime)) - - description = '' - report = ArtifactHtmlReport('Files App - iCloud Server Items') - report.start_artifact_report(report_folder, 'Files App - iCloud Server Items', description) - report.add_script() - data_headers = ('Birthtime', 'Filename', 'Version Modified Time' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Files App - iCloud Server Items' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Files App - iCloud Server Items' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Files App - iCloud Server Items data available') - diff --git a/scripts/artifacts/filesAppsm.py b/scripts/artifacts/filesAppsm.py deleted file mode 100644 index 184e65c5..00000000 --- a/scripts/artifacts/filesAppsm.py +++ /dev/null @@ -1,71 +0,0 @@ -import glob -import os -import nska_deserialize as nd -import sqlite3 -import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_filesAppsm(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('smartfolders.db'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT * - FROM - FILENAMES - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - - for row in all_rows: - - output_file = open(os.path.join(report_folder, row[2]+'.bplist'), "wb") - output_file.write(row[1]) - output_file.close() - - with open(os.path.join(report_folder, row[2]+'.bplist'), "rb") as f: - deserialized_plist = nd.deserialize_plist(f) - for x, y in deserialized_plist.items(): - if x == '_creationDate': - creationdate = y - if x == '_contentModificationDate': - contentmodificationdate = y - if x == '_flags': - flags = y - if x == '_userInfo': - userinfo = y - if x == '_childItemCount': - childitemcount = y - lasthitdate = datetime.datetime.fromtimestamp(row[3]) - - data_list.append((lasthitdate, row[0], row[2],row[4], creationdate, contentmodificationdate, userinfo, childitemcount, flags)) - - description = 'Files App - Files stored in the "On my iPad" area.' - report = ArtifactHtmlReport('Files App - Filenames') - report.start_artifact_report(report_folder, 'Files App - Filenames', description) - report.add_script() - data_headers = ('Last Hit Date','Folder ID','Filename','Frequency at Las Hit Date','Creation Date','Modification Date','User Info','Child Item Count','Flags' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Files App - Filenames' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Files App - Filenames' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Files App - Filenames data available') - - db.close() - diff --git a/scripts/artifacts/geodApplications.py b/scripts/artifacts/geodApplications.py deleted file mode 100644 index 068b29f2..00000000 --- a/scripts/artifacts/geodApplications.py +++ /dev/null @@ -1,46 +0,0 @@ -import base64 -import json -import sqlite3 -import os -import scripts.artifacts.artGlobals -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_geodApplications(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute( - """ - SELECT count_type, app_id, createtime - FROM mkcount - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[2], row[0], row[1] )) - description = '' - report = ArtifactHtmlReport('Geolocation') - report.start_artifact_report(report_folder, 'Applications', description) - report.add_script() - data_headers = ("Creation Time", "Count ID", "Application") - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape = False) - report.end_artifact_report() - - tsvname = 'Geolocation Applications' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Geolocation Applications' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No data available for Geolocation Applications') - - db.close() - return - diff --git a/scripts/artifacts/geodMapTiles.py b/scripts/artifacts/geodMapTiles.py deleted file mode 100644 index cd67982c..00000000 --- a/scripts/artifacts/geodMapTiles.py +++ /dev/null @@ -1,133 +0,0 @@ -import base64 -import gzip -import os -#import scripts.artifacts.artGlobals -import struct -import sqlite3 -import zlib - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, generate_hexdump, open_sqlite_db_readonly - -def ReadVLOC(data): - names = [] - total_len = len(data) - pos = 8 - while pos < total_len: - if data[pos] < 0x80: - skip_len = 2 - else: - skip_len = 3 - end_pos = data[pos+skip_len:].find(b'\0') - if end_pos >= 0: - name = data[pos + skip_len : pos + skip_len + end_pos].decode('utf8', 'ignore') - if name: - names.append(name) - pos += skip_len + end_pos + 1 - else: - break - return names - -def ParseTCOL(data): - '''returns tuple (VMP4 places, VLOC places)''' - tcol_places = [] - data_size = len(data) - if data_size >=8: - tcol_data_offset = struct.unpack('", tcol_places) - except (OSError, EOFError, zlib.error) as ex: - logfunc('Gzip decompression error from ParseTCOL() - ' + str(ex)) - tcol_places = '' - vmp4_places = ParseVMP4(data[8:tcol_data_offset]) - return vmp4_places, ReadVLOC(tcol_places) - -def ParseVMP4(data): - num_items = struct.unpack('", places_data.rstrip(b'\0').split(b'\0')) - return [x.decode('UTF8', 'ignore') for x in places_data.rstrip(b'\0').split(b'\0')] - pos += 10 - return [] - -def get_hex(num): - if num: - return hex(num).upper() - return '' - -def get_geodMapTiles(files_found, report_folder, seeker): - file_found = str(files_found[0]) - #os.chmod(file_found, 0o0777) - db = open_sqlite_db_readonly(file_found) - db.row_factory = sqlite3.Row - cursor = db.cursor() - cursor.execute( - """ - SELECT datetime(access_times.timestamp, 'unixepoch') as timestamp, key_a, key_b, key_c, key_d, tileset, data, size, etag - FROM data - INNER JOIN access_times on data.rowid = access_times.data_pk - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - tcol_places = '' - vmp4_places = '' - data_parsed = '' - data = row['data'] - if data: # NULL sometimes - if len(data) >= 11 and data[:11] == b'\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00': - img_base64 = base64.b64encode(data).decode('utf-8') - img_html = f'Map Tile' - data_parsed = img_html - elif len(data) >= 4 and data[:4] == b'TCOL': - vmp4_places, tcol_places = ParseTCOL(data) - vmp4_places = ", ".join(vmp4_places) - tcol_places = ", ".join(tcol_places) - elif len(data) >=4 and data[:4] == b'VMP4': - vmp4_places = ParseVMP4(data) - vmp4_places = ", ".join(vmp4_places) - #else: - #header_bytes = data[:28] - #hexdump = generate_hexdump(header_bytes, 5) if header_bytes else '' - #data_parsed = hexdump - - data_list.append((row['timestamp'], tcol_places, vmp4_places, data_parsed, get_hex(row['tileset']), - get_hex(row['key_a']), get_hex(row['key_b']), get_hex(row['key_c']), get_hex(row['key_d'])) ) - # row['size']) , row['etag'])) - description = '' - report = ArtifactHtmlReport('Geolocation') - report.start_artifact_report(report_folder, 'Map Tile Cache', description) - report.add_script() - data_headers = ("Timestamp", "Places_from_VLOC", "Labels_in_tile", "Image", "Tileset", "Key A", "Key B", "Key C", "Key D")#, "Size", "ETAG") - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape = False) - report.end_artifact_report() - - tsvname = 'Geolocation Map Tiles' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Geolocation Map tiles' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No data available for Geolocation') - - db.close() diff --git a/scripts/artifacts/geodPDPlaceCache.py b/scripts/artifacts/geodPDPlaceCache.py deleted file mode 100644 index d40f4108..00000000 --- a/scripts/artifacts/geodPDPlaceCache.py +++ /dev/null @@ -1,48 +0,0 @@ -import base64 -import json -import sqlite3 -import os -import scripts.artifacts.artGlobals -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, strings, open_sqlite_db_readonly - - -def get_geodPDPlaceCache(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute( - """ - SELECT requestkey, pdplacelookup.pdplacehash, datetime('2001-01-01', "lastaccesstime" || ' seconds') as lastaccesstime, datetime('2001-01-01', "expiretime" || ' seconds') as expiretime, pdplace - FROM pdplacelookup - INNER JOIN pdplaces on pdplacelookup.pdplacehash = pdplaces.pdplacehash - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - pd_place = ''.join(f'{row}
' for row in set(strings(row[4]))) - data_list.append((row[2], row[0], row[1], row[3], pd_place)) - description = '' - report = ArtifactHtmlReport('Geolocation') - report.start_artifact_report(report_folder, 'PD Place Cache', description) - report.add_script() - data_headers = ( "last access time", "requestkey", "pdplacehash", "expire time", "pd place") - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape = False) - report.end_artifact_report() - - tsvname = 'Geolocation PD Place Caches' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Geolocation PD Place Caches' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No data available for Geolocation PD Place Caches') - - db.close() - return - diff --git a/scripts/artifacts/googleDuo.py b/scripts/artifacts/googleDuo.py deleted file mode 100644 index 89e5ecb2..00000000 --- a/scripts/artifacts/googleDuo.py +++ /dev/null @@ -1,163 +0,0 @@ -import os -import shutil -import sqlite3 -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows, open_sqlite_db_readonly - -def get_googleDuo(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if not file_found.endswith('DataStore'): - continue - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(''' - select - datetime(contact_reg_data_timestamp/1000000, 'unixepoch'), - contact_name, - contact_id, - contact_number_label, - datetime(contact_sync_date/1000000, 'unixepoch') - from contact - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - description = 'Google Duo - Contacts' - report = ArtifactHtmlReport('Google Duo - Contacts') - report.start_artifact_report(report_folder, 'Google Duo - Contacts') - report.add_script() - data_headers = ('Registration Date','Name','ID','Number Label','Sync Date') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Google Duo - Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Google Duo - Contacts' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('Google Duo - Contacts data available') - - cursor.execute(''' - select - datetime(call_history.call_history_timestamp, 'unixepoch'), - call_history.call_history_local_user_id, - call_history.call_history_other_user_id, - contact.contact_name, - strftime('%H:%M:%S',call_history.call_history_duration, 'unixepoch'), - case call_history.call_history_is_outgoing_call - when 0 then 'Incoming' - when 1 then 'Outgoing' - end, - case call_history.call_history_is_video_call - when 0 then '' - when 1 then 'Yes' - end - from call_history - left join contact on call_history.call_history_other_user_id = contact.contact_id - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - description = 'Google Duo - Call History' - report = ArtifactHtmlReport('Google Duo - Call History') - report.start_artifact_report(report_folder, 'Google Duo - Call History') - report.add_script() - data_headers = ('Timestamp','Local User ID','Remote User ID','Contact Name','Call Duration','Call Direction','Video Call?') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Google Duo - Call History' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Google Duo - Call History' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('Google Duo - Call History data available') - - cursor.execute(''' - select - datetime(media_clip_creation_date/1000000, 'unixepoch'), - datetime(media_clip_message_date/1000000, 'unixepoch'), - datetime(media_clip_viewed_date/1000000, 'unixepoch'), - media_clip_local_id, - case media_clip_source - when 0 then 'Received' - when 1 then 'Sent' - end, - media_clip_text_representation, - media_clip_message_id, - media_clip_md5_checksum, - media_clip_content_size, - media_clip_transferred_size - from media_clip_v2 - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - - clip_creation = row[0] - clip_message = row[1] - clip_viewed = row[2] - local_id = row[3] - clip_direction = row[4] - text_rep = row[5] - message_id = row[6] - content_size = row[7] - transferred_size = row[8] - thumb = '' - - clip_name = str(message_id) + '.png' - print(clip_name) - #Check for Clips - for match in files_found: - if clip_name in match: - shutil.copy2(match, report_folder) - data_file_name = os.path.basename(match) - thumb = f'' - - data_list.append((clip_creation, clip_message, clip_viewed, local_id, clip_direction ,text_rep, message_id, content_size, transferred_size, thumb)) - - description = 'Google Duo - Clips' - report = ArtifactHtmlReport('Google Duo - Clips') - report.start_artifact_report(report_folder, 'Google Duo - Clips') - report.add_script() - data_headers = ( - 'Creation Date', 'Message Date', 'Viewed Date', 'Local User ID', 'Clip Direction','Text Representation', 'Message ID','Content Size', 'Transferred Size', 'Clip') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Clip']) - report.end_artifact_report() - - tsvname = f'Google Duo - Clips' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Google Duo - Clips' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('Google Duo - Clips data available') - - db.close() - return \ No newline at end of file diff --git a/scripts/artifacts/iCloudWifi.py b/scripts/artifacts/iCloudWifi.py deleted file mode 100644 index 2a336b66..00000000 --- a/scripts/artifacts/iCloudWifi.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import plistlib - -from datetime import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - - -def get_iCloudWifi(files_found, report_folder, seeker): - data_list = [] - file_found = str(files_found[0]) - with open(file_found, 'rb') as fp: - pl = plistlib.load(fp) - timestamp = '' - - if 'values' in pl.keys(): - for key, val in pl['values'].items(): - network_name = key - - if type(val) == dict: - for key2, val2 in val.items(): - if key2 == 'value': - if type(val2) == dict: - if 'BSSID' in val2: - bssid = str(val2['BSSID']) - else: - bssid = 'Not Available' - - if 'SSID_STR' in val2: - ssid = str(val2['SSID_STR']) - else: - ssid = 'Not Available' - - if 'added_by' in val2: - added_by = str(val2['added_by']) - else: - added_by = 'Not Available' - - if 'enabled' in val2: - enabled = str(val2['enabled']) - else: - enabled = 'Not Available' - - if 'added_at' in val2: - # Convert the value into a datetime object. - my_time2 = str(val2['added_at']) - datetime_obj = datetime.strptime(my_time2, '%b %d %Y %H:%M:%S') - added_at = str(datetime_obj) - else: - added_at = 'Not Available' - data_list.append((bssid, ssid, added_by, enabled, added_at)) - - if len(data_list) > 0: - report = ArtifactHtmlReport('iCloud Wifi Networks') - report.start_artifact_report(report_folder, 'iCloud Wifi Networks') - report.add_script() - data_headers = ('BSSID','SSID', 'Added By', 'Enabled', 'Added At') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'iCloud Wifi Networks' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data on iCloud WiFi networks') \ No newline at end of file diff --git a/scripts/artifacts/icloudMeta.py b/scripts/artifacts/icloudMeta.py deleted file mode 100644 index 3b78c36e..00000000 --- a/scripts/artifacts/icloudMeta.py +++ /dev/null @@ -1,64 +0,0 @@ -import json -import datetime -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - -def get_icloudMeta(files_found, report_folder, seeker): - counter = 0 - for file_found in files_found: - file_found = str(file_found) - counter = counter + 1 - data_list = [] - with open(file_found, "r") as filecontent: - for line in filecontent: - jsonconv = json.loads(line) - length = len(jsonconv) - for i in range(length): - docid = (jsonconv[i].get('document_id', '')) - parid = (jsonconv[i].get('parent_id', '')) - name = (jsonconv[i].get('name', '')) - typee = (jsonconv[i].get('type', '')) - deleted= (jsonconv[i].get('deleted', '')) - mtime = (jsonconv[i].get('mtime', '')) - if mtime > 0: - mtime = datetime.datetime.fromtimestamp(mtime/1000) - else: - mtime = '' - ctime = (jsonconv[i].get('ctime', '')) - if ctime > 0: - ctime = datetime.datetime.fromtimestamp(ctime/1000) - else: - ctime = '' - btime = (jsonconv[i].get('btime', '')) - if btime > 0: - btime = datetime.datetime.fromtimestamp(btime/1000) - else: - btime = '' - size = (jsonconv[i].get('size', '')) - zone = (jsonconv[i].get('zone', '')) - exe = (jsonconv[i]['file_flags'].get('is_executable', '')) - hid = (jsonconv[i]['file_flags'].get('is_hidden', '')) - lasteditor = (jsonconv[i].get('last_editor_name', '')) - if lasteditor: - lasteditorname = json.loads(jsonconv[i]['last_editor_name']) - lasteditorname = (lasteditorname.get('name', '')) - else: - lasteditorname = '' - basehash = (jsonconv[i].get('basehash', '')) - data_list.append((btime, ctime, mtime, name, lasteditorname, docid, parid, typee, deleted, size, zone, exe, hid)) - - - if len(data_list) > 0: - report = ArtifactHtmlReport('iCloud - File Metadata'+' '+str(counter)) - report.start_artifact_report(report_folder, 'iCloud - File Metadata'+' '+str(counter)) - report.add_script() - data_headers = ('Btime','Ctime','Mtime', 'Name', 'Last Editor Name', 'Doc ID', 'Parent ID', 'Type', 'Deleted?','Size', 'Zone', 'Executable?','Hidden?') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - tsvname = 'iCloud - File Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data available') diff --git a/scripts/artifacts/icloudPhotoMeta.py b/scripts/artifacts/icloudPhotoMeta.py deleted file mode 100644 index 45a2ccb7..00000000 --- a/scripts/artifacts/icloudPhotoMeta.py +++ /dev/null @@ -1,167 +0,0 @@ -import json -import datetime -import base64 -import plistlib -import os -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, kmlgen, is_platform_windows - -def timefactorconversion(timeinutc): - #timeinutc has to be a string - if (len(timeinutc) == 16): - timefactor = 1000000 - else: - timefactor = 1000 - timeinutc = int(timeinutc) - if timeinutc > 0: - timeinutc = datetime.datetime.fromtimestamp(timeinutc/timefactor) - timeinutc = str(timeinutc) - return timeinutc - -def get_icloudPhotoMeta(files_found, report_folder, seeker): - counter = 0 - os.makedirs(os.path.join(report_folder, "bplists")) - for file_found in files_found: - file_found = str(file_found) - counter = counter + 1 - data_list = [] - with open(file_found, "r") as filecontent: - for line in filecontent: - jsonconv = json.loads(line) - #print(jsonconv) - - if (isinstance(jsonconv, dict)): - jsonconv = jsonconv['results'] - length = len(jsonconv) - - for i in range(length): - #Initialize variables for when items are not located in a loop. - id = '' - created_timestamp = '' - created_user = '' - created_device = '' - modified_timestamp = '' - modified_user = '' - modified_device = '' - decoded = '' - is_deleted = '' - is_expunged = '' - org_filesize = '' - rec_mod_date = '' - import_date = '' - f_org_creation_date = '' - res_org_filesize = '' - added_date = '' - timezoneoffse = '' - latitude = '' - longitude = '' - altitude = '' - datestamp = '' - timestamp = '' - vid_name = '' - decoded_tz = '' - title = '' - recordtype = '' - tiff = '' - exif = '' - - id = (jsonconv[i].get('id', '')) - rowid = str(i) - recordtype = (jsonconv[i].get('recordType', '')) - - if (jsonconv[i].get('created', '')): - created_timestamp = (jsonconv[i]['created'].get('timestamp', '')) - created_timestamp = timefactorconversion(str(created_timestamp)) - #created_user = (jsonconv[i]['created'].get('user', '')) - #created_device = (jsonconv[i]['created'].get('device', '')) - - if(jsonconv[i].get('modified', '')): - modified_timestamp = (jsonconv[i]['modified'].get('timestamp', '')) - modified_timestamp = timefactorconversion(str(modified_timestamp)) - #modified_user = (jsonconv[i]['modified'].get('user', '')) - #modified_device = (jsonconv[i]['modified'].get('device', '')) - - if (jsonconv[i].get('fields')): - coded_string = (jsonconv[i]['fields'].get('filenameEnc', '')) #base64 - decoded = base64.b64decode(coded_string) - decoded = decoded.decode() - coded_string_tz = (jsonconv[i]['fields'].get('timeZoneNameEnc', ''))#base64 - decoded_tz = base64.b64decode(coded_string_tz) - decoded_tz = decoded_tz.decode() - is_deleted = (jsonconv[i]['fields'].get('isDeleted', '')) - is_expunged = (jsonconv[i]['fields'].get('isExpunged', '')) - org_filesize = (jsonconv[i]['fields'].get('resOriginalFileSize', '')) - res_org_filesize = (jsonconv[i]['fields'].get('resOriginalFileSize', '')) - - if (jsonconv[i]['fields'].get('originalCreationDate', '')): - created_timestamp = (jsonconv[i]['fields'].get('originalCreationDate', '')) - created_timestamp = timefactorconversion(str(created_timestamp)) - - rec_mod_date = (jsonconv[i]['fields'].get('recordModificationDate', '')) - if isinstance(rec_mod_date, int): - rec_mod_date = timefactorconversion(str(rec_mod_date)) - - import_date = (jsonconv[i]['fields'].get('importDate', '')) - if isinstance(import_date, int): - import_date = timefactorconversion(str(import_date)) - - f_org_creation_date = (jsonconv[i]['fields'].get('originalCreationDate', '')) - if isinstance(f_org_creation_date, int): - f_org_creation_date = timefactorconversion(str(f_org_creation_date)) - - added_date = (jsonconv[i]['fields'].get('addedDate', '')) - if isinstance(added_date, int): - added_date = timefactorconversion(str(added_date)) - - timezoneoffse = (jsonconv[i]['fields'].get('timeZoneOffse', '')) - title = (jsonconv[i]['fields'].get('title', '')) - decodedt = base64.b64decode(title) - title = decodedt.decode() - - coded_bplist = (jsonconv[i]['fields'].get('mediaMetaDataEnc')) #convert from base64 to bplist and process - if coded_bplist is not None: - decoded_bplist = base64.b64decode(coded_bplist) - # If needed send the full bplist to report folder by editing the outputpath below - with open(os.path.join(report_folder, "bplists", rowid + ".bplist"), 'wb') as g: - g.write(decoded_bplist) - pl = plistlib.loads(decoded_bplist) - if (pl.get('{TIFF}')): - #print('YESS TIFF # '+str(i)) - tiff = (pl.get('{TIFF}')) - exif = (pl.get('{Exif}')) - - if (pl.get('{GPS}')) is not None: - #print(pl['{GPS}']) - latitude = (pl['{GPS}'].get('Latitude')) - longitude = (pl['{GPS}'].get('Longitude')) - altitude = (pl['{GPS}'].get('Altitude')) - datestamp = (pl['{GPS}'].get('DateStamp')) - timestamp = (pl['{GPS}'].get('TimeStamp')) - #print(latitude) - else: - if (pl.get('moop')): #If needed send binary content to report flder - pass - #with open(f'{outputpath}/{i}.moop', 'wb') as g: - # g.write(pl.get('moop')) - - data_list.append((created_timestamp, rowid, recordtype, decoded, title, org_filesize, latitude,longitude,altitude,datestamp,timestamp,added_date, timezoneoffse, decoded_tz ,is_deleted,is_expunged, import_date, rec_mod_date,res_org_filesize, id, tiff, exif)) - - - if len(data_list) > 0: - report = ArtifactHtmlReport('iCloud - Photos Metadata'+' '+str(counter)) - report.start_artifact_report(report_folder, 'iCloud - Photos Metadata'+' '+str(counter)) - report.add_script() - data_headers = ('Timestamp', 'Row ID','Record Type','Decoded', 'Title', 'Filesize', 'Latitude', 'Longitude', 'Altitude', 'GPS Datestamp','GPS Time', 'Added Date', 'Timezone Offset','Decoded TZ', 'Is Deleted?','Is Expunged?','Import Date', 'Modification Date', 'Filesize', 'ID', 'TIFF', 'EXIF') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - tsvname = 'iCloud - Photos Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - - kmlactivity = 'iCloud - Photos Metadata' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - else: - logfunc('No data available') - \ No newline at end of file diff --git a/scripts/artifacts/icloudSharedalbums.py b/scripts/artifacts/icloudSharedalbums.py deleted file mode 100644 index 09a316b5..00000000 --- a/scripts/artifacts/icloudSharedalbums.py +++ /dev/null @@ -1,161 +0,0 @@ -import plistlib -import os -from pathlib import Path - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - -def get_icloudSharedalbums(files_found, report_folder, seeker): - data_list_sharedemails = [] - data_list_sharedpersoninfos = [] - data_list_sharedinfos = [] - data_list_cloudinfo = [] - - for file_found in files_found: - file_found = str(file_found) - pathedhead, pathedtail = os.path.split(file_found) - - if os.path.isfile(file_found): - if pathedtail == 'cloudSharedEmails.plist': - with open(file_found, "rb") as fp: - pl = plistlib.load(fp) - for x, y in pl.items(): - data_list_sharedemails.append((x, y)) - - elif pathedtail == 'cloudSharedPersonInfos.plist': - with open(file_found, "rb") as fp: - pl = plistlib.load(fp) - for x, y in pl.items(): - - email = '' - firstname = '' - lastname = '' - fullname = '' - - for a, b in y.items(): - if a == 'email': - email = b - if a == 'firstName': - firstname = b - if a == 'fullName': - fullname = b - if a == 'emails': - email = b[0] - if a == 'lastName': - lastname = b - - file_found_persons = file_found - data_list_sharedpersoninfos.append((email, firstname, lastname, fullname, x)) - - elif pathedtail == 'Info.plist': - albumid = (os.path.basename(os.path.dirname(file_found))) - albumpath = file_found - #print(f'Info.plist album ID: {albumid}') - - cloudOwnerEmail = '' - - with open(file_found, "rb") as fp: - pl = plistlib.load(fp) - - cloudOwnerEmail = '' - cloudownerfirstname = '' - cloudownerlastname = '' - cloudpublicurlenabled = '' - cloudsubscriptiondate = '' - cloudrelationshipstate = '' - cloudownerhashedpersonid = '' - clowdoenweremail = '' - title = '' - - for x, y in pl.items(): - #print(f'{x}: {y}') - if x == 'cloudOwnerEmail': - clowdoenweremail = y - if x == 'cloudOwnerFirstName': - cloudownerfirstname = y - if x == 'cloudOwnerLastName': - cloudownerlastname = y - if x == 'cloudPublicURLEnabled': - cloudpublicurlenabled = y - if x == 'cloudSubscriptionDate': - cloudsubscriptiondate = y - if x == 'cloudRelationshipState': - cloudrelationshipstate = y - if x == 'title': - albumtitle = y - if x == 'cloudOwnerHashedPersonID': - cloudownerhashedpersonid = y - - data_list_sharedinfos.append((albumtitle, albumid, clowdoenweremail, cloudownerfirstname, cloudownerlastname, cloudpublicurlenabled, cloudsubscriptiondate, cloudrelationshipstate, cloudownerhashedpersonid, albumpath)) - - elif pathedtail == 'DCIM_CLOUD.plist': - albumid = (os.path.basename(os.path.dirname(file_found))) - albumpath = file_found - #print(f'Info.plist album ID: {albumid}') - with open(file_found, "rb") as fp: - pl = plistlib.load(fp) - for x, y in pl.items(): - if x == 'DCIMLastDirectoryNumber': - dcimlastdictnum = y - if x == 'DCIMLastFileNumber': - dcimlastfilenum = y - data_list_cloudinfo.append((albumid, dcimlastdictnum, dcimlastfilenum, albumpath)) - - else: - pass - - if len(data_list_sharedinfos) > 0: - location = 'See report entry' - report = ArtifactHtmlReport('iCloud Shared Owner Info') - report.start_artifact_report(report_folder, 'iCloud Shared Owner Info') - report.add_script() - data_headers = ('Album Title','Album ID','Clowd Owner Email','Cloud Owner First Name','Clowd Owner Lastname','Cloud Public URL Enabled?','Cloud Subscription Date','Cloud Relationship State','Cloud Ownewr Hashed Person ID', 'File location' ) - report.write_artifact_data_table(data_headers, data_list_sharedinfos, location) - report.end_artifact_report() - - tsvname = 'iCloud Shared Owner Info' - tsv(report_folder, data_headers, data_list_sharedinfos, tsvname) - else: - logfunc('No iCloud Shared Owner Info') - - if len(data_list_cloudinfo) > 0: - location = 'See report entry' - report = ArtifactHtmlReport('iCloud Shared Album data') - report.start_artifact_report(report_folder, 'iCloud Shared Album Data') - report.add_script() - data_headers = ('Album Name', 'DCIM Last Directory Number','DCIM LAst File Number', 'File location' ) - report.write_artifact_data_table(data_headers, data_list_cloudinfo, location) - report.end_artifact_report() - - tsvname = 'iCloud Shared Album Data' - tsv(report_folder, data_headers, data_list_cloudinfo, tsvname) - else: - logfunc('No iCloud Shared Album Data') - - if len(data_list_sharedpersoninfos) > 0: - location = file_found_persons - report = ArtifactHtmlReport('iCloud Shared Album Persons Info') - report.start_artifact_report(report_folder, 'iCloud Shared Person Info') - report.add_script() - data_headers = ('Email', 'Firstname','Lastname', 'Fullname', 'Identification' ) - report.write_artifact_data_table(data_headers, data_list_sharedpersoninfos, location) - report.end_artifact_report() - - tsvname = 'iCloud Shared Person Info' - tsv(report_folder, data_headers, data_list_sharedpersoninfos, tsvname) - else: - logfunc('No iCloud Shared Album Persons Info') - - if len(data_list_sharedemails) > 0: - location = file_found - report = ArtifactHtmlReport('iCloud Shared Albums Emails') - report.start_artifact_report(report_folder, 'iCloud Shared Emails') - report.add_script() - data_headers = ('Key', 'Value' ) - report.write_artifact_data_table(data_headers, data_list_sharedemails, location) - report.end_artifact_report() - - tsvname = 'iCloud Shared Albums Emails' - tsv(report_folder, data_headers, data_list_sharedemails, tsvname) - else: - logfunc('No iCloud Shared Emails') \ No newline at end of file diff --git a/scripts/artifacts/iconsScreen.py b/scripts/artifacts/iconsScreen.py deleted file mode 100644 index 582c2268..00000000 --- a/scripts/artifacts/iconsScreen.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import plistlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, is_platform_windows - -def get_iconsScreen(files_found, report_folder, seeker): - data_list = [] - data_pre_list = [] - file_found = str(files_found[0]) - with open(file_found, "rb") as fp: - plist = plistlib.load(fp) - for key, val in plist.items(): - if key == "buttonBar": - bbar = val - elif key == "iconLists": - icon = val - - for x in range(0, len(icon)): - page = icon[x] - htmlstring = (f"") - htmlstring = htmlstring + (f'') - for y in range(0, len(page)): - rows = page[y] - if (y == 0) or (y % 4 == 0): - htmlstring = htmlstring + ("") - - if isinstance(rows, dict): - var = rows - foldername = var['displayName'] - rows = (f'Folder: {foldername}') - bundlesinfolder = var['iconLists'][0] - for items in bundlesinfolder: - rows = rows + '
' + items - - htmlstring = htmlstring + (f"") - htmlstring = htmlstring + ("
Icons screen #{x}
{rows}
") - data_list.append((htmlstring,)) - - htmlstring = '' - htmlstring = (f'') - for x in range(0, len(bbar)): - htmlstring = htmlstring +(f"") - htmlstring = htmlstring +("
Icons bottom bar
{bbar[x]}
") - data_list.append((htmlstring,)) - - logfunc("Screens: " + str(len(icon))) - - report = ArtifactHtmlReport(f'Apps per screen') - report.start_artifact_report(report_folder, f'Apps per screen') - report.add_script() - data_headers = ((f'Apps per Screens',)) - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - \ No newline at end of file diff --git a/scripts/artifacts/imoHD_Chat.py b/scripts/artifacts/imoHD_Chat.py deleted file mode 100644 index 255c93ed..00000000 --- a/scripts/artifacts/imoHD_Chat.py +++ /dev/null @@ -1,148 +0,0 @@ -import sqlite3 -import io -import json -import os -import shutil -import nska_deserialize as nd -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_imoHD_Chat(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - case ZIMOCHATMSG.ZTS - when 0 then '' - else datetime(ZTS/1000000000,'unixepoch') - end as "Timestamp", - ZIMOCONTACT.ZDISPLAY as "Sender Display Name", - ZIMOCHATMSG.ZALIAS as "Sender Alias", - ZIMOCONTACT.ZDIGIT_PHONE, - ZIMOCHATMSG.ZTEXT as "Message", - case ZIMOCHATMSG.ZISSENT - when 0 then 'Received' - when 1 then 'Sent' - end as "Message Status", - ZIMOCHATMSG.ZIMDATA - from ZIMOCHATMSG - left join ZIMOCONTACT ON ZIMOCONTACT.ZBUID = ZIMOCHATMSG.ZA_UID - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - - plist = '' - timestamp = row[0] - senderName = row[1] - senderAlias = row[2] - senderPhone = row[3] - message = row[4] - messageStatus = row[5] - itemAction = '' - attachmentURL = '' - thumb = '' - - plist_file_object = io.BytesIO(row[6]) - if row[6] is None: - pass - else: - if row[6].find(b'NSKeyedArchiver') == -1: - if sys.version_info >= (3, 9): - plist = plistlib.load(plist_file_object) - else: - plist = biplist.readPlist(plist_file_object) - else: - try: - plist = nd.deserialize_plist(plist_file_object) - except (nd.DeserializeError, nd.biplist.NotBinaryPlistException, nd.biplist.InvalidPlistException, - nd.plistlib.InvalidFileException, nd.ccl_bplist.BplistError, ValueError, TypeError, OSError, OverflowError) as ex: - logfunc(f'Failed to read plist for {row[0]}, error was:' + str(ex)) - - itemAction = plist['type'] - - #Check for Attachments - if plist.get('objects') is not None: - attachmentName = plist['objects'][0]['object_id'] - attachmentURL = "https://cdn.imoim.us/s/object/" + attachmentName + "/" - - for match in files_found: - if attachmentName in match: - shutil.copy2(match, report_folder) - data_file_name = os.path.basename(match) - thumb = f'' - - else: - attachmentURL = '' - - data_list.append((timestamp, senderName, senderAlias, senderPhone, message, messageStatus, itemAction, attachmentURL, thumb)) - - description = 'IMO HD Chat - Messages' - report = ArtifactHtmlReport('IMO HD Chat - Messages') - report.start_artifact_report(report_folder, 'IMO HD Chat - Messages') - report.add_script() - data_headers = ( - 'Timestamp', 'Sender Name', 'Sender Alias', 'Sender Phone', 'Message', 'Message Status', 'Item Action', - 'Attachment URL', 'Attachment') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Attachment']) - report.end_artifact_report() - - tsvname = f'IMO HD Chat - Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'IMO HD Chat - Messages' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('IMO HD Chat - Messages data available') - - cursor.execute(''' - select - ZPH_NAME, - ZALIAS, - ZPHONE, - "https://cdn.imoim.us/s/object/" || ZICON_ID || "/" as "Profile Pic", - ZBUID - from ZIMOCONTACT - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - description = 'IMO HD Chat - Contacts' - report = ArtifactHtmlReport('IMO HD Chat - Contacts') - report.start_artifact_report(report_folder, 'IMO HD Chat - Contacts') - report.add_script() - data_headers = ('Contact Name','Contact Alias','Contact Phone','Profile Pic URL','User ID') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4])) - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'IMO HD Chat - Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'IMO HD Chat - Contacts' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('IMO HD Chat - Contacts data available') - - db.close() diff --git a/scripts/artifacts/instagramThreads.py b/scripts/artifacts/instagramThreads.py deleted file mode 100644 index 89bd472b..00000000 --- a/scripts/artifacts/instagramThreads.py +++ /dev/null @@ -1,182 +0,0 @@ -import sqlite3 -import io -import json -import nska_deserialize as nd -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_instagramThreads(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.db'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - metadata - from threads - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - fila = 0 - userdict = {} - data_list = [] - video_calls = [] - - if usageentries > 0: - for row in all_rows: - plist = '' - plist_file_object = io.BytesIO(row[0]) - if row[0].find(b'NSKeyedArchiver') == -1: - if sys.version_info >= (3, 9): - plist = plistlib.load(plist_file_object) - else: - plist = biplist.readPlist(plist_file_object) - else: - try: - plist = nd.deserialize_plist(plist_file_object) - except (nd.DeserializeError, nd.biplist.NotBinaryPlistException, nd.biplist.InvalidPlistException, - nd.plistlib.InvalidFileException, nd.ccl_bplist.BplistError, ValueError, TypeError, OSError, OverflowError) as ex: - logfunc(f'Failed to read plist for {row[0]}, error was:' + str(ex)) - - for i in plist['NSArray*users']: - for x, y in enumerate(plist['NSArray*users']): - userPk = plist['NSArray*users'][x]['pk'] - userFull = (plist['NSArray*users'][x]['fullName']) - userdict[userPk] = userFull - - inviterPk = plist['IGUser*inviter']['pk'] - inviterFull = plist['IGUser*inviter']['fullName'] - userdict[inviterPk] = inviterFull - - cursor.execute(''' - select - messages.message_id, - messages.thread_id, - messages.archive, - threads.metadata, - threads.thread_messages_range, - threads.visual_message_info - from messages, threads - where messages.thread_id = threads.thread_id - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - - if usageentries > 0: - for row in all_rows: - plist = '' - senderpk ='' - serverTimestamp = '' - message = '' - videoChatTitle = '' - videoChatCallID = '' - dmreaction = '' - reactionServerTimestamp = '' - reactionUserID = '' - sharedMediaID = '' - sharedMediaURL = '' - - plist_file_object = io.BytesIO(row[2]) - if row[2].find(b'NSKeyedArchiver') == -1: - if sys.version_info >= (3, 9): - plist = plistlib.load(plist_file_object) - else: - plist = biplist.readPlist(plist_file_object) - else: - try: - plist = nd.deserialize_plist(plist_file_object) - except (nd.DeserializeError, nd.biplist.NotBinaryPlistException, nd.biplist.InvalidPlistException, - nd.plistlib.InvalidFileException, nd.ccl_bplist.BplistError, ValueError, TypeError, OSError, OverflowError) as ex: - logfunc(f'Failed to read plist for {row[2]}, error was:' + str(ex)) - - #Messages - senderpk = plist['IGDirectPublishedMessageMetadata*metadata']['NSString*senderPk'] - serverTimestamp = plist['IGDirectPublishedMessageMetadata*metadata']['NSDate*serverTimestamp'] - message = plist['IGDirectPublishedMessageContent*content'].get('NSString*string') - - #VOIP calls - if plist['IGDirectPublishedMessageContent*content'].get('IGDirectThreadActivityAnnouncement*threadActivity') is not None: - videoChatTitle = plist['IGDirectPublishedMessageContent*content']['IGDirectThreadActivityAnnouncement*threadActivity'].get('NSString*voipTitle') - videoChatCallID = plist['IGDirectPublishedMessageContent*content']['IGDirectThreadActivityAnnouncement*threadActivity'].get('NSString*videoCallId') - - - #Reactions - reactions = (plist['NSArray*reactions']) - if reactions: - dmreaction = reactions[0].get('emojiUnicode') - reactionServerTimestamp = reactions[0].get('serverTimestamp') - reactionUserID = reactions[0].get('userId') - - #Shared media - if (plist['IGDirectPublishedMessageContent*content'].get('IGDirectPublishedMessageMedia*media')): - try: - sharedMediaID = plist['IGDirectPublishedMessageContent*content']['IGDirectPublishedMessageMedia*media']['IGDirectPublishedMessagePermanentMedia*permanentMedia']['IGPhoto*photo']['kIGPhotoMediaID'] - except (KeyError, ValueError, TypeError, OSError, OverflowError) as ex: - print('Had exception: ' + str(ex)) - sharedMediaID = None - - try: - sharedMediaURL = plist['IGDirectPublishedMessageContent*content']['IGDirectPublishedMessageMedia*media']['IGDirectPublishedMessagePermanentMedia*permanentMedia']['IGPhoto*photo']['imageVersions'][0]['url']['NS.relative'] - except (KeyError, ValueError, TypeError, OSError, OverflowError) as ex: - print('Had exception: ' + str(ex)) - sharedMediaURL= None - - if senderpk in userdict: - user = userdict[senderpk] - else: - user = '' - - data_list.append((serverTimestamp, senderpk, user, message, videoChatTitle, videoChatCallID, dmreaction, reactionServerTimestamp, reactionUserID, sharedMediaID, sharedMediaURL)) - if videoChatTitle: - video_calls.append((serverTimestamp, senderpk, user, videoChatTitle, videoChatCallID)) - - description = 'Instagram Threads' - report = ArtifactHtmlReport('Instagram Threads') - report.start_artifact_report(report_folder, 'Instagram Threads', description) - report.add_script() - data_headers = ('Timestamp', 'Sender ID', 'Username', 'Message', 'Video Chat Title', 'Video Chat ID', 'DM Reaction', 'DM Reaction Server Timestamp', 'Reaction User ID', 'Shared Media ID', 'Shared Media URL') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Instagram Threads' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Instagram Threads' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Instagram Threads data available') - - if len(video_calls) > 0: - description = 'Instagram Threads Calls' - report = ArtifactHtmlReport('Instagram Threads Calls') - report.start_artifact_report(report_folder, 'Instagram Threads Calls', description) - report.add_script() - data_headersv = ('Timestamp', 'Sender ID', 'Username', 'Video Chat Title', 'Video Chat ID') - report.write_artifact_data_table(data_headersv, video_calls, file_found) - report.end_artifact_report() - - tsvname = 'Instagram Threads Calls' - tsv(report_folder, data_headersv, video_calls, tsvname) - - tlactivity = 'Instagram Threads Calls' - timeline(report_folder, tlactivity, video_calls, data_headersv) - - else: - logfunc('No Instagram Threads Video Calls data available') - - db.close() - - - - \ No newline at end of file diff --git a/scripts/artifacts/interactionCcontacts.py b/scripts/artifacts/interactionCcontacts.py deleted file mode 100644 index 287df835..00000000 --- a/scripts/artifacts/interactionCcontacts.py +++ /dev/null @@ -1,105 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf -from packaging import version #use to search per version number - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def get_interactionCcontacts(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - - iOSversion = scripts.artifacts.artGlobals.versionf - if version.parse(iOSversion) >= version.parse("10"): - cursor = db.cursor() - cursor.execute(''' - select - datetime(zinteractions.zstartdate + 978307200, 'unixepoch'), - datetime(zinteractions.zenddate + 978307200, 'unixepoch'), - zinteractions.zbundleid, - zcontacts.zdisplayname, - zcontacts.zidentifier, - zinteractions.zdirection, - zinteractions.zisresponse, - zinteractions.zrecipientcount, - datetime(zinteractions.zcreationdate + 978307200, 'unixepoch'), - datetime(zcontacts.zcreationdate + 978307200, 'unixepoch'), - zinteractions.zcontenturl - from - zinteractions - left join - zcontacts - on zinteractions.zsender = zcontacts.z_pk - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - - if version.parse(iOSversion) >= version.parse("10"): - for row in all_rows: data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8],row[9],row[10])) - - report = ArtifactHtmlReport('InteractionC') - report.start_artifact_report(report_folder, 'Contacts') - report.add_script() - data_headers = ('Start Date','End Date','Bundle ID','Display Name','Identifier','Direction','Is Response','Recipient Count','Zinteractions Creation Date','Zcontacs Creation Date','Content URL') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'InteractionC Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'InteractonC Contacts' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data available in InteractionC Contacts') - - if version.parse(iOSversion) >= version.parse("10"): - cursor = db.cursor() - cursor.execute(''' - select - datetime(zinteractions.ZCREATIONDATE + 978307200, 'unixepoch'), - ZINTERACTIONS.zbundleid, - ZINTERACTIONS.ztargetbundleid, - ZINTERACTIONS.zuuid, - ZATTACHMENT.zcontenturl - from zinteractions - inner join z_1interactions - on zinteractions.z_pk = z_1interactions.z_3interactions - inner join zattachment on z_1interactions.z_1attachments = zattachment.z_pk - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - - if version.parse(iOSversion) >= version.parse("10"): - for row in all_rows: data_list.append((row[0],row[1],row[2],row[3],row[4])) - - report = ArtifactHtmlReport('InteractionC') - report.start_artifact_report(report_folder, 'Attachments') - report.add_script() - data_headers = ('Creation Date', 'Bundle ID', 'Target Bundle ID', 'ZUUID', 'Content URL') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'InteractionC Attachments' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'InteractionC Attachments' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data available in InteractionC Attachments') - - - db.close() - return - - - \ No newline at end of file diff --git a/scripts/artifacts/keyboardAppUsage.py b/scripts/artifacts/keyboardAppUsage.py deleted file mode 100644 index cb81fce6..00000000 --- a/scripts/artifacts/keyboardAppUsage.py +++ /dev/null @@ -1,33 +0,0 @@ -import plistlib - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline - - -def get_keyboardAppUsage(files_found, report_folder, seeker): - data_list = [] - - for file_found in files_found: - file_found = str(file_found) - with open(file_found, "rb") as plist_file: - plist_content = plistlib.load(plist_file) - for app in plist_content: - for entry in plist_content[app]: - data_list.append((entry['startDate'], app, entry['appTime'], ', '.join(map(str, entry['keyboardTimes'])))) - - if len(data_list) > 0: - report = ArtifactHtmlReport('Keyboard Application Usage') - report.start_artifact_report(report_folder, 'Keyboard Application Usage') - report.add_script() - data_headers = ('Date', 'Application Name', 'Application Time Used in Seconds', 'Keyboard Times Used in Seconds') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Keyboard Application Usage' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Keyboard Application Usage' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Keyboard Application Usage found') \ No newline at end of file diff --git a/scripts/artifacts/keyboardLexicon.py b/scripts/artifacts/keyboardLexicon.py deleted file mode 100644 index fb38a71d..00000000 --- a/scripts/artifacts/keyboardLexicon.py +++ /dev/null @@ -1,53 +0,0 @@ -import string -from os.path import dirname - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline - - -def get_keyboardLexicon(files_found, report_folder, seeker): - data_list = [] - tsv_data_list = [] - for file_found in files_found: - strings_list = [] - with open(file_found, 'rb') as dat_file: - dat_content = dat_file.read() - dat_content_decoded = str(dat_content, 'utf-8', 'ignore') - found_str = '' - for char in dat_content_decoded: - if char in string.printable: - found_str += char - else: - if found_str: - if len(found_str) > 2: # reduce noise - strings_list.append(found_str) - found_str = '' - - if file_found.find("Keyboard/") >= 0: - slash = '/' - else: - slash = '\\' - location_file_found = file_found.split(f"Keyboard{slash}", 1)[1] - data_list.append(('
'.join(strings_list), location_file_found)) - tsv_data_list.append((','.join(strings_list), location_file_found)) - - dir_file_found = dirname(file_found).split('Keyboard', 1)[0] + 'Keyboard' - - if data_list: - report = ArtifactHtmlReport('Keyboard Dynamic Lexicon') - report.start_artifact_report(report_folder, 'Keyboard Dynamic Lexicon') - report.add_script() - data_headers = ('Found Strings', 'File Location') - report.write_artifact_data_table(data_headers, data_list, dir_file_found, html_no_escape=['Found Strings']) - report.end_artifact_report() - - tsvname = 'Keyboard Dynamic Lexicon' - tsv(report_folder, data_headers, tsv_data_list, tsvname) - - tlactivity = 'Keyboard Dynamic Lexicon' - timeline(report_folder, tlactivity, tsv_data_list, data_headers) - - else: - logfunc('No Keyboard Dynamic Lexicon data found') - - return diff --git a/scripts/artifacts/kikBplistmeta.py b/scripts/artifacts/kikBplistmeta.py deleted file mode 100644 index 950f3ea6..00000000 --- a/scripts/artifacts/kikBplistmeta.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 - -import os -import biplist - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - - -def get_kikBplistmeta(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - isDirectory = os.path.isdir(file_found) - if isDirectory: - pass - else: - sha1org = sha1scaled = blockhash = appname = layout = allowforward = filesize = filename = thumb = appid = id = '' - with open(file_found, 'rb') as f: - plist = biplist.readPlist(f) - for key,val in plist.items(): - if key == 'id': - id = val - elif key == 'hashes': - for x in val: - if x['name'] == 'sha1-original': - sha1org = x.get('value', '') - if x['name'] == 'sha1-scaled': - sha1scaled = x.get('value', '') - if x['name'] == 'blockhash-scaled': - blockhash = x.get('value', '') - elif key == 'string': - for x in val: - if x['name'] == 'app-name': - appname = x.get('value', '') - if x['name'] == 'layout': - layout = x.get('value', '') - if x['name'] == 'allow-forward': - allowforward = x.get('value', '') - if x['name'] == 'file-size': - filesize = x.get('value', '') - if x['name'] == 'file-name': - filename = x.get('value', '') - elif key == 'image': - thumbfilename = id+'.jpg' - file = open(f'{report_folder}{thumbfilename}', "wb") - file.write(val[0]['value']) - file.close() - thumb = f'' - elif key == 'app-id': - appid = val - - data_list.append((id, filename, filesize, allowforward, layout, appname, appid, sha1org, sha1scaled, blockhash, thumb )) - aggregate = '' - - if len(data_list) > 0: - head_tail = os.path.split(file_found) - description = 'Metadata from Kik media directory. Source are bplist files.' - report = ArtifactHtmlReport('Kik Attachments Bplist Metadata') - report.start_artifact_report(report_folder, 'Kik Media Metadata', description) - report.add_script() - data_headers = ('Content ID ', 'Filename', 'File Size', 'Allow Forward', 'Layout','App Name','App ID', 'SHA1 Original','SHA1 Scaled','Blockhash Scaled', 'Internal Thumbnail') - report.write_artifact_data_table(data_headers, data_list, head_tail[0],html_escape=False) - report.end_artifact_report() - - tsvname = 'Kik Attachments Bplist Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data on Kik Attachments Bplist MetadataD') \ No newline at end of file diff --git a/scripts/artifacts/kikMessages.py b/scripts/artifacts/kikMessages.py deleted file mode 100644 index 9a6fec80..00000000 --- a/scripts/artifacts/kikMessages.py +++ /dev/null @@ -1,117 +0,0 @@ -import os -import shutil -import sqlite3 -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_kikMessages(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - datetime(ZKIKMESSAGE.ZRECEIVEDTIMESTAMP +978307200,'UNIXEPOCH') AS RECEIVEDTIME, - datetime(ZKIKMESSAGE.ZTIMESTAMP +978307200,'UNIXEPOCH') as TIMESTAMP, - ZKIKMESSAGE.ZBODY, - case ZKIKMESSAGE.ZTYPE - when 1 then 'Received' - when 2 then 'Sent' - when 3 then 'Group Admin' - when 4 then 'Group Message' - else 'Unknown' end as 'Type', - ZKIKMESSAGE.ZUSER, - ZKIKUSER.ZDISPLAYNAME, - ZKIKUSER.ZUSERNAME, - ZKIKATTACHMENT.ZCONTENT - from ZKIKMESSAGE - left join ZKIKUSER on ZKIKMESSAGE.ZUSER = ZKIKUSER.Z_PK - left join ZKIKATTACHMENT on ZKIKMESSAGE.Z_PK = ZKIKATTACHMENT.ZMESSAGE - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - - attachmentName = str(row[7]) - thumb = '' - - for match in files_found: - if attachmentName in match: - shutil.copy2(match, report_folder) - data_file_name = os.path.basename(match) - thumb = f'' - - - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], thumb)) - - description = 'Kik Messages' - report = ArtifactHtmlReport('Kik Messages') - report.start_artifact_report(report_folder, 'Kik Messages', description) - report.add_script() - data_headers = ('Received Time', 'Timestamp', 'Message', 'Type', 'User', 'Display Name', 'User Name','Attachment Name','Attachment') - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Attachment']) - report.end_artifact_report() - - tsvname = 'Kik Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Kik Messages' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Kik Messages data available') - - cursor.execute(''' - SELECT - Z_PK, - ZDISPLAYNAME, - ZUSERNAME, - ZEMAIL, - ZJID, - ZFIRSTNAME, - ZLASTNAME, - datetime(ZPPTIMESTAMP/1000,'unixepoch'), - ZPPURL - FROM ZKIKUSER - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8])) - - description = 'Kik Users' - report = ArtifactHtmlReport('Kik Users') - report.start_artifact_report(report_folder, 'Kik Users', description) - report.add_script() - data_headers = ('PK','Display Name','User Name','Email','JID','First Name','Last Name','Profile Pic Timestamp','Profile Pic URL') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Kik Users' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Kik Users' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Kik Users data available') - - db.close() - return - - diff --git a/scripts/artifacts/kikPendingUploads.py b/scripts/artifacts/kikPendingUploads.py deleted file mode 100644 index 3165c245..00000000 --- a/scripts/artifacts/kikPendingUploads.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil -import xml.etree.ElementTree as ET -import scripts.artifacts.artGlobals - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - - -def get_kikPendingUploads(files_found, report_folder, seeker): - data_list = [] - appID = '' - contentID = '' - progress = '' - retriesRemaining = '' - state = '' - uploadStartTime = '' - thumb = '' - - for file_found in files_found: - file_found = str(file_found) - - if not file_found.endswith('pending_uploads'): - continue - - tree = ET.parse(file_found) - root = tree.getroot() - a_dict = {} - counter = 0 - for elem in root: - for subelem in elem: - for subelem2 in subelem: - - if counter == 0: - key = subelem2.text - a_dict[key] = '' - counter += 1 - else: - value = subelem2.text - a_dict[key] = value - counter = 0 - - appID = a_dict['appID'] - contentID = a_dict['contentID'] - progress = a_dict['progress'] - retriesRemaining = a_dict['retriesRemaining'] - state = a_dict['state'] - uploadStartTime = a_dict['uploadStartTime'] - - thumb = f'' - - data_list.append((uploadStartTime, appID, contentID, progress, retriesRemaining, state, thumb)) - - a_dict = {} - - if len(data_list) > 0: - - for match in files_found: - if contentID in match: - shutil.copy2(match, report_folder) - - # for x in len(data_list): - # for match in files_found: - # if contentID in match: - # shutil.copy2(match, report_folder) - # data_file_name = os.path.basename(match) - # thumb = f'' - - # data_list.append((uploadStartTime, appID, contentID, progress, retriesRemaining, state, thumb)) - - head_tail = os.path.split(file_found) - description = 'Metadata from Kik media directory. Source are bplist files.' - report = ArtifactHtmlReport('Kik Pending Uploads') - report.start_artifact_report(report_folder, 'Kik Pending Uploads', description) - report.add_script() - data_headers = ('Upload Start Time','App ID','Content ID','Progress','Retries Remaining','State','Pending File') - report.write_artifact_data_table(data_headers, data_list, head_tail[0],html_no_escape=['Pending File']) - report.end_artifact_report() - - tsvname = 'Kik Pending Uploads' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No data on Kik Pending Uploads') \ No newline at end of file diff --git a/scripts/artifacts/kikUsersgroups.py b/scripts/artifacts/kikUsersgroups.py deleted file mode 100644 index 7df752e6..00000000 --- a/scripts/artifacts/kikUsersgroups.py +++ /dev/null @@ -1,79 +0,0 @@ -import glob -import os -import nska_deserialize as nd -import sqlite3 -import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_kikUsersgroups(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('kik.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - Select ZKIKUSER.Z_PK, /*User ID*/ - ZKIKUSER.ZDISPLAYNAME, /*Display Name*/ - ZKIKUSER.ZUSERNAME, /*Username, if available*/ - ZKIKUSER.ZPPURL, /*Profile Picture URL*/ - Z_9MEMBERS.Z_9MEMBERSINVERSE, /*Group ID of group where user is a member. */ - Z_9ADMINSINVERSE.Z_9ADMINSINVERSE, /*Group ID of group where user is an administrator. */ - ZKIKUSEREXTRA.ZENTITYUSERDATA, /*BLOB from ZKIKUSEREXTRA that contains additional user information. */ - ZKIKUSEREXTRA.ZROSTERENTRYDATA /*Field from ZKIKUSEREXTRA that contains additional user information*/ - From ZKIKUSER - INNER Join Z_9MEMBERS On ZKIKUSER.Z_PK = Z_9MEMBERS.Z_9MEMBERS /*(joined Z_PK from ZKIKUSER table with Z_9MEMBERS in Z_9MEMBERS table)*/ - Left Join Z_9ADMINSINVERSE On ZKIKUSER.Z_PK = Z_9ADMINSINVERSE.Z_9ADMINS /*(matched Z_PK from ZKIKUSER table with Z_9ADMINS from Z_9ADMINSINVERSE table)*/ - LEFT JOIN ZKIKUSEREXTRA On ZKIKUSER.Z_PK = ZKIKUSEREXTRA.ZUSER /*(matched Z_PK from ZKIKUSER with ZUSER from ZKIKUSEREXTRA)*/ - Order By Z_9MEMBERS.Z_9MEMBERSINVERSE, Z_9ADMINSINVERSE.Z_9ADMINSINVERSE DESC /*sorted by Group ID, then Admin status*/ - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - - for row in all_rows: - - cursor2 = db.cursor() - cursor2.execute(f''' - SELECT ZGROUPTAG, - ZDISPLAYNAME, - ZJID, - ZPPURL - FROM ZKIKUSER - WHERE Z_PK = {row[4]} - ''') - - all_rows2 = cursor2.fetchall() - for rows2 in all_rows2: - grouptag = rows2[0] - groupdname = rows2[1] - zjid = rows2[2] - zpurl = rows2[3] - - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],grouptag,groupdname,zjid, zpurl,row[6],row[7])) - - - description = 'Kik users that are members of a group.' - report = ArtifactHtmlReport('Kik Users in Groups') - report.start_artifact_report(report_folder, 'Kik Users in Groups', description) - report.add_script() - data_headers = ('User ID','Display Name','Username','Profile Pic URL','Member Group ID','Administrator Group ID','Group Tag','Group Name','Group ID','Group Pic URL','Blob','Additional Information') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Kik Users' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('No Files App - iCloud Sync Names data available') - - - - \ No newline at end of file diff --git a/scripts/artifacts/locServicesconfig.py b/scripts/artifacts/locServicesconfig.py deleted file mode 100644 index e7ccfe02..00000000 --- a/scripts/artifacts/locServicesconfig.py +++ /dev/null @@ -1,109 +0,0 @@ -import os -import plistlib -import datetime -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def convertcocoa(timevalue): - if timevalue == '': - return '' - else: - unix = datetime.datetime(1970, 1, 1) # UTC - cocoa = datetime.datetime(2001, 1, 1) - delta = cocoa - unix # timedelta instance - timestamp = datetime.datetime.fromtimestamp(timevalue) + delta - return (timestamp.strftime('%Y-%m-%d %H:%M:%S')) - -def get_locServicesconfig(files_found, report_folder, seeker): - - data_list_clientsplist = [] - data_list_routinedplist= [] - data_list_locationdplist = [] - - for file_found in files_found: - if file_found.endswith('clients.plist'): - with open(file_found,'rb') as f : - clientsplist = plistlib.load(f) - - if file_found.endswith('com.apple.locationd.plist'): - with open(file_found,'rb') as f : - locationdplist = plistlib.load(f) - - if file_found.endswith('com.apple.routined.plist'): - with open(file_found,'rb') as f : - routinedplist = plistlib.load(f) - - - for key, value in clientsplist.items(): - if key == 'com.apple.locationd.bundle-/System/Library/LocationBundles/Routine.bundle': - fencetimestarted = convertcocoa(value.get('FenceTimeStarted', '')) - comsumptionperiod = convertcocoa(value.get('ConsumptionPeriodBegin', '')) - receivinglocationinformationtimestopped = convertcocoa(value.get('ReceivingLocationInformationTimeStopped', '')) - authorization = value.get('Authorization', '') - locationtimestopped = convertcocoa(value.get('LocationTimeStopped', '')) - - data_list_clientsplist.append((fencetimestarted, 'FenceTimeStarted')) - data_list_clientsplist.append((comsumptionperiod, 'ConsumptionPeriodBegin')) - data_list_clientsplist.append((receivinglocationinformationtimestopped, 'ReceivingLocationInformationTimeStopped')) - data_list_clientsplist.append((authorization, 'Authorization')) - data_list_clientsplist.append((locationtimestopped, 'LocationTimeStopped')) - - - for key, value in locationdplist.items(): - data_list_locationdplist.append((key, value)) - - for key, value in routinedplist.items(): - if key != 'CloudKitAccountInfoCache': - data_list_routinedplist.append((value, key)) - - if len(data_list_routinedplist) > 0: - report = ArtifactHtmlReport('LSC - com.apple.routined.plist') - report.start_artifact_report(report_folder, 'LSC - com.apple.routined.plist') - report.add_script() - data_headers = ('Value', 'Key') - report.write_artifact_data_table(data_headers, data_list_routinedplist, file_found) - report.end_artifact_report() - - tsvname = 'LSC - com.apple.routined.plist' - tsv(report_folder, data_headers, data_list_routinedplist, tsvname) - - tlactivity = 'LSC - com.apple.routined.plist' - timeline(report_folder, tlactivity, data_list_routinedplist, data_headers) - - else: - logfunc('No LSC - com.apple.routined.plist') - - if len(data_list_locationdplist) > 0: - report = ArtifactHtmlReport('LSC - com.apple.locationd.plist') - report.start_artifact_report(report_folder, 'LSC - com.apple.locationd.plist') - report.add_script() - data_headers = ('Value', 'Key') - report.write_artifact_data_table(data_headers, data_list_locationdplist, file_found) - report.end_artifact_report() - - tsvname = 'LSC - com.apple.locationd.plist' - tsv(report_folder, data_headers, data_list_locationdplist, tsvname) - - tlactivity = 'LSC - com.apple.locationd.plist' - timeline(report_folder, tlactivity, data_list_locationdplist, data_headers) - - else: - logfunc('No LSC - com.apple.locationd.plist') - - if len(data_list_clientsplist) > 0: - report = ArtifactHtmlReport('LSC - clients.plist') - report.start_artifact_report(report_folder, 'LSC - clients.plist') - report.add_script() - data_headers = ('Value', 'Key') - report.write_artifact_data_table(data_headers, data_list_clientsplist, file_found) - report.end_artifact_report() - - tsvname = 'LSC - clients.plist' - tsv(report_folder, data_headers, data_list_clientsplist, tsvname) - - tlactivity = 'LSC - clients.plist' - timeline(report_folder, tlactivity, data_list_clientsplist, data_headers) - - else: - logfunc('No LSC - clients.plist') - \ No newline at end of file diff --git a/scripts/artifacts/mailprotect.py b/scripts/artifacts/mailprotect.py deleted file mode 100644 index 40f4822d..00000000 --- a/scripts/artifacts/mailprotect.py +++ /dev/null @@ -1,214 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import json -import textwrap -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows -from scripts.parse3 import ParseProto - -def get_mailprotect(files_found, report_folder, seeker): - iOSversion = scripts.artifacts.artGlobals.versionf - - if version.parse(iOSversion) <= version.parse("11"): - logfunc("Unsupported version for iOS emails in iOS " + iOSversion) - return () - - if version.parse(iOSversion) < version.parse("13"): - head, end = os.path.split(files_found[0]) - db = sqlite3.connect(os.path.join(report_folder, "emails.db")) - cursor = db.cursor() - cursor.execute( - """ - create table email1(rowid int, ds text, dr text, size int, sender text, messid int, subject text, receipt text, cc text, bcc text) - """ - ) - db.commit() - - cursor.execute( - """ - create table email2(rowid int, data text) - """ - ) - db.commit() - db.close() - - db = sqlite3.connect(os.path.join(head, "Envelope Index")) - db.execute(f'ATTACH DATABASE "{head}/Protected Index" AS PI') - db.execute(f'ATTACH DATABASE "{report_folder}/emails.db" AS emails') - - cursor = db.cursor() - cursor.execute( - """ - select - main.messages.ROWID, - main.messages.date_sent, - main.messages.date_received, - main.messages.size, - PI.messages.sender, - PI.messages.message_id, - PI.messages.subject, - PI.messages._to, - PI.messages.cc, - PI.messages.bcc - from main.messages, PI.messages - where main.messages.ROWID = PI.messages.message_id - """ - ) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - print(f"Total emails {usageentries}") - for row in all_rows: - # print(row) - datainsert = ( - row[0], - row[1], - row[2], - row[3], - row[4], - row[5], - row[6], - row[7], - row[8], - row[9], - ) - cursor.execute( - "INSERT INTO emails.email1 (rowid, ds, dr, size, sender, messid, subject, receipt, cc, bcc) VALUES (?,?,?,?,?,?,?,?,?,?)", - datainsert, - ) - db.commit() - else: - print("Zero rows") - - cursor = db.cursor() - cursor.execute( - """ - select - main.messages.ROWID, - PI.message_data.data - from main.message_data, main.messages, PI.messages, PI.message_data - where main.messages.ROWID = main.message_data.message_id and PI.messages.message_id = main.message_data.message_id - and PI.message_data.message_data_id = main.message_data.ROWID - """ - ) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - print(f"Total emails with message data {usageentries}") - for row in all_rows: - datainsert = ( - row[0], - row[1], - ) - cursor.execute( - "INSERT INTO emails.email2 (rowid, data) VALUES(?,?)", - datainsert, - ) - db.commit() - else: - print("Zero rows") - - cursor.execute( - """ - select - email1.rowid, - datetime(email1.ds, 'unixepoch') as ds, - datetime(email1.dr, 'unixepoch') as dr, - email1.sender, - email1.messid, - email1.subject, - email1.receipt, - email1.cc, - email1.bcc, - email2.data - from email1 - left outer join email2 - on email2.rowid = email1.rowid - """ - ) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - data_list.append((row[1],row[2],row[3],row[4],row[5],row[6],row[9],row[7],row[8],row[0])) - - file_found = head - description = '' - report = ArtifactHtmlReport('iOS Mail') - report.start_artifact_report(report_folder, 'Emails', description) - report.add_script() - data_headers = ('Date Sent','Date Received','Sender','Message ID', 'Subject', 'Recipient', 'Message', 'CC', 'BCC','Row ID') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'iOS Mail' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'iOS Mail' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc("No iOS emails available") - db.close() - - if version.parse(iOSversion) >= version.parse("13"): - head, end = os.path.split(files_found[0]) - db = sqlite3.connect(os.path.join(head, "Envelope Index")) - db.execute(f'ATTACH DATABASE "{head}/Protected Index" AS PI') - - cursor = db.cursor() - cursor.execute( - """ - SELECT - datetime(main.messages.date_sent, 'UNIXEPOCH') as datesent, - datetime(main.messages.date_received, 'UNIXEPOCH') as datereceived, - PI.addresses.address, - PI.addresses.comment, - PI.subjects.subject, - PI.summaries.summary, - main.messages.read, - main.messages.flagged, - main.messages.deleted, - main.mailboxes.url - from main.mailboxes, main.messages, PI.subjects, PI.addresses, PI.summaries - where main.messages.subject = PI.subjects.ROWID - and main.messages.sender = PI.addresses.ROWID - and main.messages.summary = PI.summaries.ROWID - and main.mailboxes.ROWID = main.messages.mailbox - """ - ) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8],row[9])) - - file_found = head - description = '' - report = ArtifactHtmlReport('iOS Mail') - report.start_artifact_report(report_folder, 'Emails', description) - report.add_script() - data_headers = ('Date Sent','Date Received','Address','Comment','Subject', 'Summary', 'Read?', 'Flagged?', 'Deleted', 'Mailbox') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'iOS Mail' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'iOS Mail' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc("No iOS emails available") - diff --git a/scripts/artifacts/mediaLibrary.py b/scripts/artifacts/mediaLibrary.py deleted file mode 100644 index 49eaccc8..00000000 --- a/scripts/artifacts/mediaLibrary.py +++ /dev/null @@ -1,112 +0,0 @@ -import os -import sys -import sqlite3 -import time -import datetime -import re - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows, open_sqlite_db_readonly - -def get_mediaLibrary(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - # Execute query for retrieving media information - try: - cursor.execute( - """ - SELECT ext.title, ext.media_kind, itep.format, - ext.location, ext.total_time_ms, ext.file_size, ext.year, - alb.album, alba.album_artist, com.composer, gen.genre, - ite.track_number, art.artwork_token, - itev.extended_content_rating, itev.movie_info, - ext.description_long, sto.account_id, - strftime(\'%d/%m/%Y %H:%M:%S\', - datetime(sto.date_purchased + 978397200, \'unixepoch\')) - date_purchased, sto.store_item_id, sto.purchase_history_id, ext.copyright - from item_extra - ext join item_store sto using (item_pid) - join item ite using (item_pid) - join item_stats ites using (item_pid) - join item_playback itep using (item_pid) - join item_video itev using (item_pid) - left join album alb on sto.item_pid=alb.representative_item_pid - left join album_artist alba - on sto.item_pid=alba.representative_item_pid - left join composer com on - sto.item_pid=com.representative_item_pid - left join genre gen on sto.item_pid=gen.representative_item_pid - left join item_artist itea on - sto.item_pid=itea.representative_item_pid - left join artwork_token art on sto.item_pid=art.entity_pid - """ - ) - except: - logfunc('Error executing SQLite query') - - all_rows = cursor.fetchall() - data_list = [] - media_type = '' - - for row in all_rows: - col_count = 0 - tmp_row = [] - - for media_type in row: - if col_count == 1: - if media_type == 0: - media_type = "E-book" - if media_type == 1: - media_type = "Audio" - if media_type == 2: - media_type = "Film" - if media_type == 33: - media_type = "Video M4V" - if media_type == 4: - media_type = "Podcast" - if col_count == 4: - media_type = int(media_type) - - col_count = col_count + 1 - tmp_row.append(str(media_type).replace('\n', '')) - - data_list.append(tmp_row) - - # Recover account information - data_list_info = [] - cursor.execute( - """ - select * from _MLDATABASEPROPERTIES; - """ - ) - iOS_info = cursor.fetchall() - - iCloud_items = [ - 'MLJaliscoAccountID', 'MPDateLastSynced', - 'MPDateToSyncWithUbiquitousStore', 'OrderingLanguage'] - - for row in iOS_info: - for elm in iCloud_items: - if row[0] == elm: - data_list_info.append((row[0],row[1])) - - report = ArtifactHtmlReport('Media Library') - report.start_artifact_report(report_folder, 'Media Library') - report.add_script() - data_headers_info = ('key', 'value') - data_headers = ('Title','Media Type','File Format','File','Total Time (ms)', - 'File Size','Year','Album Name','Album Artist','Composer', - 'Genre','Track Number', 'Artwork','Content Rating', - 'Movie Information','Description','Account ID', - 'Date Purchased','Item ID','Purchase History ID','Copyright') - - report.write_artifact_data_table(data_headers_info, data_list_info, file_found, cols_repeated_at_bottom=False) - report.write_artifact_data_table(data_headers, data_list, file_found, True, False) - - report.end_artifact_report() - - tsvname = 'Media Library' - tsv(report_folder, data_headers_info, data_list_info, tsvname) - tsv(report_folder, data_headers, data_list, tsvname) - diff --git a/scripts/artifacts/medicalID.py b/scripts/artifacts/medicalID.py deleted file mode 100644 index fbeaccb3..00000000 --- a/scripts/artifacts/medicalID.py +++ /dev/null @@ -1,51 +0,0 @@ -import biplist -import pathlib -import os -import nska_deserialize as nd - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - -def get_name(name_with_prefix): - retval = name_with_prefix - if name_with_prefix.startswith('HKMedicalIDData'): - retval = name_with_prefix[15:] - if retval.endswith('Key'): - retval = retval[:-3] - return retval - -def get_medicalID(files_found, report_folder, seeker): - data_list = [] - file_found = str(files_found[0]) - with open(file_found, 'rb') as f: - deserialized_plist = nd.deserialize_plist(f) - for key, value in deserialized_plist.items(): - key_name = get_name(key) - if isinstance(value, dict): - unit = value.get('UnitKey', {}).get('HKUnitStringKey', '') - val = str(value.get('ValueKey', '')) - if unit: - val += ' ' + unit - data_list.append((key_name, val)) - elif isinstance(value, list): - # not seen! - data_list.append((key_name, str(value))) - else: - data_list.append((key_name, value)) - - if len(data_list) > 0: - description = 'User entered Medical information about self' - report = ArtifactHtmlReport('Medical ID') - report.start_artifact_report(report_folder, 'Health Info', description) - report.add_script() - data_headers = ('Key', 'Value') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Medical ID' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Medical ID' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data on Medical ID') \ No newline at end of file diff --git a/scripts/artifacts/mobileActivationLogs.py b/scripts/artifacts/mobileActivationLogs.py deleted file mode 100644 index e0388dd3..00000000 --- a/scripts/artifacts/mobileActivationLogs.py +++ /dev/null @@ -1,75 +0,0 @@ -import os -import re -import pathlib - -from datetime import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - - -def get_mobileActivationLogs(files_found, report_folder, seeker): - data_list = [] - data_list_info = [] - - source_files = [] - for file_found in files_found: - file_found = str(file_found) - if file_found.startswith('\\\\?\\'): - file_name = pathlib.Path(file_found[4:]).name - source_files.append(file_found[4:]) - else: - file_name = pathlib.Path(file_found).name - source_files.append(file_found) - - with open(file_found, 'r') as fp: - data = fp.readlines() - linecount = 0 - hitcount = 0 - activationcount = 0 - - for line in data: - linecount += 1 - date_filter = re.compile(r'(([A-Za-z]+[\s]+([a-zA-Z]+[\s]+[0-9]+)[\s]+([0-9]+\:[0-9]+\:[0-9]+)[\s]+([0-9]{4}))([\s]+[\[\d\]]+[\s]+[\]+[\s]+[\(\w\)]+[\s]+[A-Z]{2}\:[\s]+)([main\:\s]*.*)$)') - line_match = re.match(date_filter, line) - - if line_match: - date_time = (line_match.group(3, 5, 4)) - conv_time = ' '.join(date_time) - dtime_obj = datetime.strptime(conv_time, '%b %d %Y %H:%M:%S') - ma_datetime = str(dtime_obj) - values = line_match.group(7) - - if 'perform_data_migration' in values: - hitcount += 1 - upgrade_match = re.search((r'((.*)(Upgrade\s+from\s+[\w]+\s+to\s+[\w]+\s+detected\.$))'), values) - if upgrade_match: - upgrade = upgrade_match.group(3) - data_list.append((ma_datetime, upgrade, file_name)) - - if '____________________ Mobile Activation Startup _____________________' in values: - activationcount += 1 - ma_startup_line = str(linecount) - ma_startup = (f'Mobile Activation Startup at line: {ma_startup_line}') - data_list.append((ma_datetime, ma_startup, file_name)) - - upgrade_entries = (f'Found {hitcount} Upgrade entries in {file_name}') - boot_entries = (f'Found {activationcount} Mobile Activation entries in {file_name}') - data_list_info.append((boot_entries, upgrade_entries)) - - report = ArtifactHtmlReport('Mobile Activation Logs') - report.start_artifact_report(report_folder, 'Mobile Activation Logs') - report.add_script() - data_headers_info = ('Mobile Activation', 'Upgrade') - data_headers = ('Datetime', 'Event', 'Log Name') - - source_files_found = ', '.join(source_files) - - report.write_artifact_data_table(data_headers_info, data_list_info, source_files_found, cols_repeated_at_bottom=False) - report.write_artifact_data_table(data_headers, data_list, source_files_found, True, False) - report.end_artifact_report() - - tsvname = 'Mobile Activation Logs' - tsv(report_folder, data_headers, data_list, tsvname) - tsv(report_folder, data_headers_info, data_list_info, tsvname) - \ No newline at end of file diff --git a/scripts/artifacts/mobileBackup.py b/scripts/artifacts/mobileBackup.py deleted file mode 100644 index 9b1a86ee..00000000 --- a/scripts/artifacts/mobileBackup.py +++ /dev/null @@ -1,46 +0,0 @@ -import os -import plistlib - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - - -# Backup version of iOS, iOS version installed at the time of recovery, -# recovery date, and whether the backup was restored from iCloud. -def get_mobileBackup(files_found, report_folder, seeker): - data_list = [] - file_found = str(files_found[0]) - - with open(file_found, 'rb') as fp: - pl = plistlib.load(fp) - - if 'BackupStateInfo' in pl.keys(): - for key, val in pl['BackupStateInfo'].items(): - if key == 'isCloud': - data_list.append((key, val)) - if key == 'date': - data_list.append((key, val)) - else: - pass - - if 'RestoreInfo' in pl.keys(): - for key, val in pl['RestoreInfo'].items(): - if key == 'BackupBuildVersion': - data_list.append((key, val)) - if key == 'DeviceBuildVersion': - data_list.append((key, val)) - if key == 'WasCloudRestore': - data_list.append((key, val)) - if key == 'RestoreDate': - data_list.append((key, val)) - - - report = ArtifactHtmlReport('Mobile Backup') - report.start_artifact_report(report_folder, 'Mobile Backup') - report.add_script() - data_headers = ('Key', 'Value') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Mobile Backup' - tsv(report_folder, data_headers, data_list, tsvname) \ No newline at end of file diff --git a/scripts/artifacts/mobileContainerManager.py b/scripts/artifacts/mobileContainerManager.py deleted file mode 100644 index 4ffb174d..00000000 --- a/scripts/artifacts/mobileContainerManager.py +++ /dev/null @@ -1,50 +0,0 @@ -import plistlib -import re - -from datetime import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows - -def get_mobileContainerManager(files_found, report_folder, seeker): - - data_list = [] - - for file_found in files_found: - - linecount = 0 - hitcount = 0 - with open(file_found, 'r') as fp: - data = fp.readlines() - - for line in data: - linecount += 1 - - if '[MCMGroupManager _removeGroupContainersIfNeededforUser:groupContainerClass:identifiers:referenceCounts:]: Last reference to group container' in line: - hitcount += 1 - txts = line.split() - dayofweek = txts[0] - month = txts[1] - day = txts[2] - time = txts[3] - year = txts[4] - group = txts[15] - - datetime_object = datetime.strptime(month, "%b") - month_number = datetime_object.month - concat_date = year + "-" + str(month_number) + "-" + day + " " + time - dtime_obj = datetime.strptime(concat_date, '%Y-%m-%d %H:%M:%S') - - data_list.append((str(dtime_obj), group, str(linecount))) - - - report = ArtifactHtmlReport('Mobile Container Manager') - report.start_artifact_report(report_folder, 'Mobile Container Manager') - report.add_script() - data_headers = ('Datetime', 'Removed', 'Line') - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Mobile Container Manager' - tsv(report_folder, data_headers, data_list, tsvname) \ No newline at end of file diff --git a/scripts/artifacts/mobileInstall.py b/scripts/artifacts/mobileInstall.py deleted file mode 100644 index 881cc58a..00000000 --- a/scripts/artifacts/mobileInstall.py +++ /dev/null @@ -1,634 +0,0 @@ -import os -import textwrap -import datetime -import sys -import re -import string -import sqlite3 -from html import escape - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - - -def month_converter(month): - months = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ] - month = months.index(month) + 1 - if month < 10: - month = f"{month:02d}" - return month - - -def day_converter(day): - day = int(day) - if day < 10: - day = f"{day:02d}" - return day - - -def get_mobileInstall(files_found, report_folder, seeker): - counter = 0 - filescounter = 0 - tsv_tml_data_list = [] - - mibdatabase = os.path.join(report_folder, 'mib.db') - db = sqlite3.connect(mibdatabase) - cursor = db.cursor() - cursor.execute( - """ - CREATE TABLE dimm(time_stamp TEXT, action TEXT, bundle_id TEXT, path TEXT) - """ - ) - - db.commit() - - for filename in files_found: - file = open(filename, "r", encoding="utf8") - filescounter = filescounter + 1 - for line in file: - counter = counter + 1 - matchObj = re.search( - r"(Install Successful for)", line - ) # Regex for installed applications - if matchObj: - actiondesc = "Install successful" - matchObj1 = re.search( - r"(?<= for \(Placeholder:)(.*)(?=\))", line - ) # Regex for bundle id - matchObj2 = re.search( - r"(?<= for \(Customer:)(.*)(?=\))", line - ) # Regex for bundle id - matchObj3 = re.search( - r"(?<= for \(System:)(.*)(?=\))", line - ) # Regex for bundle id - matchObj4 = re.search( - r"(?<= for \()(.*)(?=\))", line - ) # Regex for bundle id - if matchObj1: - bundleid = matchObj1.group(1) - elif matchObj2: - bundleid = matchObj2.group(1) - elif matchObj3: - bundleid = matchObj3.group(1) - elif matchObj4: - bundleid = matchObj4.group(1) - - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - # logfunc(inserttime, actiondesc, bundleid) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - bundleid, - "", - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - path = '' - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - - # logfunc() - - matchObj = re.search( - r"(Destroying container with identifier)", line - ) # Regex for destroyed containers - if matchObj: - actiondesc = "Destroying container" - # logfunc(actiondesc) - # logfunc("Destroyed containers:") - matchObj = re.search( - r"(?<=identifier )(.*)(?= at )", line - ) # Regex for bundle id - if matchObj: - bundleid = matchObj.group(1) - # logfunc ("Bundle ID: ", bundleid ) - - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - matchObj = re.search(r"(?<= at )(.*)(?=$)", line) # Regex for path - if matchObj: - path = matchObj.group(1) - # logfunc ("Path: ", matchObj.group(1)) - - # logfunc(inserttime, actiondesc, bundleid, path) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - bundleid, - path, - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - # logfunc() - - matchObj = re.search( - r"(Data container for)", line - ) # Regex Moved data containers - if matchObj: - actiondesc = "Data container moved" - # logfunc(actiondesc) - # logfunc("Data container moved:") - matchObj = re.search( - r"(?<=for )(.*)(?= is now )", line - ) # Regex for bundle id - if matchObj: - bundleid = matchObj.group(1) - # logfunc ("Bundle ID: ", bundleid ) - - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - matchObj = re.search(r"(?<= at )(.*)(?=$)", line) # Regex for path - if matchObj: - path = matchObj.group(1) - # logfunc ("Path: ", matchObj.group(1)) - - # logfunc(inserttime, actiondesc, bundleid, path) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - bundleid, - path, - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - # logfunc() - - matchObj = re.search( - r"(Made container live for)", line - ) # Regex for made container - if matchObj: - actiondesc = "Made container live" - # logfunc(actiondesc) - # logfunc("Made container:") - matchObj = re.search( - r"(?<=for )(.*)(?= at)", line - ) # Regex for bundle id - if matchObj: - bundleid = matchObj.group(1) - # logfunc ("Bundle ID: ", bundleid ) - - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - matchObj = re.search(r"(?<= at )(.*)(?=$)", line) # Regex for path - if matchObj: - path = matchObj.group(1) - # logfunc ("Path: ", matchObj.group(1)) - # logfunc(inserttime, actiondesc, bundleid, path) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - bundleid, - path, - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - - matchObj = re.search( - r"(Uninstalling identifier )", line - ) # Regex for made container - if matchObj: - actiondesc = "Uninstalling identifier" - # logfunc(actiondesc) - # logfunc("Uninstalling identifier") - matchObj = re.search( - r"(?<=Uninstalling identifier )(.*)", line - ) # Regex for bundle id - if matchObj: - bundleid = matchObj.group(1) - # logfunc ("Bundle ID: ", bundleid ) - - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - bundleid, - "", - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - - matchObj = re.search(r"(main: Reboot detected)", line) # Regex for reboots - if matchObj: - actiondesc = "Reboot detected" - # logfunc(actiondesc) - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - "", - "", - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - - matchObj = re.search( - r"(Attempting Delta patch update of )", line - ) # Regex for Delta patch - if matchObj: - actiondesc = "Attempting Delta patch" - # logfunc(actiondesc) - # logfunc("Made container:") - matchObj = re.search( - r"(?<=Attempting Delta patch update of )(.*)(?= from)", line - ) # Regex for bundle id - if matchObj: - bundleid = matchObj.group(1) - # logfunc ("Bundle ID: ", bundleid ) - - matchObj = re.search(r"(?<=^)(.*)(?= \[)", line) # Regex for timestamp - if matchObj: - timestamp = matchObj.group(1) - weekday, month, day, time, year = str.split(timestamp) - day = day_converter(day) - month = month_converter(month) - inserttime = ( - str(year) + "-" + str(month) + "-" + str(day) + " " + str(time) - ) - # logfunc(inserttime) - # logfunc(month) - # logfunc(day) - # logfunc(year) - # logfunc(time) - # logfunc ("Timestamp: ", timestamp) - - matchObj = re.search(r"(?<= from )(.*)", line) # Regex for path - if matchObj: - path = matchObj.group(1) - # logfunc ("Path: ", matchObj.group(1)) - # logfunc(inserttime, actiondesc, bundleid, path) - - # insert to database - cursor = db.cursor() - datainsert = ( - inserttime, - actiondesc, - bundleid, - path, - ) - cursor.execute( - "INSERT INTO dimm (time_stamp, action, bundle_id, path) VALUES(?,?,?,?)", - datainsert, - ) - db.commit() - - tsv_tml_data_list.append((inserttime, actiondesc, bundleid, path)) - # logfunc() - - logfunc(f"Logs processed: {filescounter}") - logfunc(f"Lines processed: {counter}") - logfunc("") - file.close - - # Initialize counters - totalapps = 0 - installedcount = 0 - uninstallcount = 0 - historicalcount = 0 - sysstatecount = 0 - - # created folders for reports for App history - os.makedirs(os.path.join(report_folder, "Apps_Historical")) - - data_list_installed = [] - data_list_uninstalled = [] - - # Initialize database connection - db = sqlite3.connect(mibdatabase) - cursor = db.cursor() - # Query to create installed and uninstalled app reports - cursor.execute("""SELECT distinct bundle_id from dimm""") - all_rows = cursor.fetchall() - for row in all_rows: - # logfunc(row[0]) - distinctbundle = row[0] - cursor.execute( - """SELECT * from dimm where bundle_id=? order by time_stamp desc limit 1""", - (distinctbundle,), - ) - all_rows_iu = cursor.fetchall() - for row in all_rows_iu: - # logfunc(row[0], row[1], row[2], row[3]) - if row[2] == "": - continue - elif row[1] == "Destroying container": - # logfunc(row[0], row[1], row[2], row[3]) - uninstallcount = uninstallcount + 1 - totalapps = totalapps + 1 - # tofile1 = row[0] + ' ' + row[1] + ' ' + row[2] + ' ' + row[3] + '\n' - data_list_uninstalled.append((row[0], row[2],)) - # logfunc() - elif row[1] == "Uninstalling identifier": - # logfunc(row[0], row[1], row[2], row[3]) - uninstallcount = uninstallcount + 1 - totalapps = totalapps + 1 - # tofile1 = row[0] + ' ' + row[1] + ' ' + row[2] + ' ' + row[3] + '\n' - data_list_uninstalled.append((row[0], row[2],)) - # logfunc() - else: - # logfunc(row[0], row[1], row[2], row[3]) - data_list_installed.append((row[0], row[2],)) - installedcount = installedcount + 1 - totalapps = totalapps + 1 - - location = f'{filename}' - description = 'List of Uninstalled apps.' - report = ArtifactHtmlReport('Apps - Uninstalled') - report.start_artifact_report(report_folder, 'Apps - Uninstalled', description) - report.add_script() - data_headers = ('Last Uninstalled', 'Bundle ID',) - report.write_artifact_data_table(data_headers, data_list_uninstalled, location) - report.end_artifact_report() - - location = f'{filename}' - description = 'List of Installed apps.' - report = ArtifactHtmlReport('Apps - Installed') - report.start_artifact_report(report_folder, 'Apps - Installed', description) - report.add_script() - data_headers = ('Last Installed', 'Bundle ID',) - report.write_artifact_data_table(data_headers, data_list_installed, location) - report.end_artifact_report() - - # Query to create historical report per app - - cursor.execute("""SELECT distinct bundle_id from dimm""") - all_rows = cursor.fetchall() - for row in all_rows: - # logfunc(row[0]) - distinctbundle = row[0] - if row[0] == "": - continue - else: - f3 = open(os.path.join(report_folder, "Apps_Historical", distinctbundle + ".txt"), - "w+", - encoding="utf8" - ) # Create historical app report per app - cursor.execute( - """SELECT * from dimm where bundle_id=? order by time_stamp DESC""", - (distinctbundle,), - ) # Query to create app history per bundle_id - all_rows_hist = cursor.fetchall() - for row in all_rows_hist: - # logfunc(row[0], row[1], row[2], row[3]) - tofile3 = row[0] + " " + row[1] + " " + row[2] + " " + row[3] + "\n" - f3.write(tofile3) - f3.close() - historicalcount = historicalcount + 1 - - list = [] - data_list = [] - path = os.path.join(report_folder, "Apps_Historical") - files = os.listdir(path) - for name in files: - bun = (f'{name}') - appendval = ( - f'Report') - data_list.append((bun, appendval)) - - location = f'{filename}' - description = 'Historical App report from the Mobile Installation Logs. All timestamps are in Local Time' - report = ArtifactHtmlReport('Apps - Historical') - report.start_artifact_report(report_folder, 'Apps - Historical', description) - report.add_script() - data_headers = ('Bundle ID', 'Report Link') - tsv_data_headers = ('Bundle ID', 'Report Link') - report.write_artifact_data_table(data_headers, data_list, location, html_escape=False) - report.end_artifact_report() - - tsvname = 'Mobile Installation Logs - History' - tsv(report_folder, tsv_data_headers, tsv_tml_data_list, tsvname) - tlactivity = 'Mobile Installation Logs - History' - tml_data_headers = ('Timestamp', 'Event', 'Bundle ID', 'Event Path') - timeline(report_folder, tlactivity, tsv_tml_data_list, tml_data_headers) - - # All event historical in html report - description = 'Historical App report from the Mobile Installation Logs. All timestamps are in Local Time' - report = ArtifactHtmlReport('Apps - Historical') - report.start_artifact_report(report_folder, 'Apps - Historical Combined', description) - report.add_script() - data_headers = ('Timestamp', 'Event', 'Bundle ID', 'Event Path') - report.write_artifact_data_table(data_headers, tsv_tml_data_list, location) - report.end_artifact_report() - - # Query to create system events - data_list_reboots = [] - cursor.execute( - """SELECT * from dimm where action ='Reboot detected' order by time_stamp DESC""" - ) - all_rows = cursor.fetchall() - for row in all_rows: - # logfunc(row[0]) - # logfunc(row[0], row[1], row[2], row[3]) - data_list_reboots.append((row[0], row[1])) - sysstatecount = sysstatecount + 1 - - if len(all_rows) > 0: - location = f'{filename}' - description = 'Reboots detected in Local Time.' - report = ArtifactHtmlReport('State - Reboots') - report.start_artifact_report(report_folder, 'State - Reboots', description) - report.add_script() - data_headers_reboots = ('Timestamp (Local Time)', 'Description') - report.write_artifact_data_table(data_headers_reboots, data_list_reboots, location) - report.end_artifact_report() - - tsvname = 'Mobile Installation Logs - Reboots' - tsv(report_folder, data_headers_reboots, data_list_reboots, tsvname) - - logfunc(f"Total apps: {totalapps}") - logfunc(f"Total installed apps: {installedcount}") - logfunc(f"Total uninstalled apps: {uninstallcount}") - logfunc(f"Total historical app reports: {historicalcount}") - logfunc(f"Total system state events: {sysstatecount}") - - ''' - data_headers_reboots = ('Timestamp (Local Time)', 'Description') - tsv_data_headers = ('Timestamp (Local Time)', 'Action', 'Bundle ID', 'Path') - - tsvname = 'Mobile Installation Logs - Reboots' - tsv(report_folder, data_headers_reboots, data_list_reboots, tsvname) - - tlactivity = 'Mobile Installation Logs - Reboots' - timeline(report_folder, tlactivity, data_list_reboots, data_headers_reboots) - - tsvname = 'Mobile Installation Logs - History' - tsv(report_folder, tsv_data_headers, tsv_tml_data_list, tsvname) - - tlactivity = 'Mobile Installation Logs - History' - timeline(report_folder, tlactivity, tsv_tml_data_list, tsv_data_headers) - ''' - - -''' - - x = 0 - data_list =[] - for file_found in files_found: - x = x + 1 - sx = str(x) - journalName = os.path.basename(file_found) - outputpath = os.path.join(report_folder, sx+'_'+journalName+'.txt') # name of file in txt - #linkpath = os.path.basename( - level2, level1 = (os.path.split(outputpath)) - level2 = (os.path.split(level2)[1]) - final = level2+'/'+level1 - with open(outputpath, 'w') as g: - for s in strings(file_found): - g.write(s) - g.write('\n') - - out = (f'{journalName}') - - data_list.append((out, file_found)) - - location ='' - description = 'ASCII and Unicode strings extracted from SQLite journaing files.' - report = ArtifactHtmlReport('Strings - SQLite Journal') - report.start_artifact_report(report_folder, 'Strings - SQLite Journal', description) - report.add_script() - data_headers = ('Report', 'Location') - report.write_artifact_data_table(data_headers, data_list, location, html_escape=False) - report.end_artifact_report() -''' diff --git a/scripts/artifacts/notes.py b/scripts/artifacts/notes.py deleted file mode 100644 index e6b9691c..00000000 --- a/scripts/artifacts/notes.py +++ /dev/null @@ -1,104 +0,0 @@ -from os.path import dirname, join -from PIL import Image -import imghdr - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_notes(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - DATETIME(TabA.ZCREATIONDATE1+978307200,'UNIXEPOCH'), - TabA.ZTITLE1, - TabA.ZSNIPPET, - TabB.ZTITLE2, - TabC.ZNAME, - DATETIME(TabA.ZMODIFICATIONDATE1+978307200,'UNIXEPOCH'), - case TabA.ZISPASSWORDPROTECTED - when 0 then "No" - when 1 then "Yes" - end, - TabA.ZPASSWORDHINT, - case TabA.ZMARKEDFORDELETION - when 0 then "No" - when 1 then "Yes" - end, - case TabA.ZISPINNED - when 0 then "No" - when 1 then "Yes" - end, - TabE.ZFILENAME, - TabE.ZIDENTIFIER, - TabD.ZFILESIZE, - TabD.ZTYPEUTI, - DATETIME(TabD.ZCREATIONDATE+978307200,'UNIXEPOCH'), - DATETIME(TabD.ZMODIFICATIONDATE+978307200,'UNIXEPOCH') - FROM ZICCLOUDSYNCINGOBJECT TabA - INNER JOIN ZICCLOUDSYNCINGOBJECT TabB on TabA.ZFOLDER = TabB.Z_PK - INNER JOIN ZICCLOUDSYNCINGOBJECT TabC on TabA.ZACCOUNT3 = TabC.Z_PK - LEFT JOIN ZICCLOUDSYNCINGOBJECT TabD on TabA.Z_PK = TabD.ZNOTE - LEFT JOIN ZICCLOUDSYNCINGOBJECT TabE on TabD.Z_PK = TabE.ZATTACHMENT1 - WHERE TabA.ZTITLE1 <> '' - ''') - - all_rows = cursor.fetchall() - analyzed_file = file_found - - if len(all_rows) > 0: - for row in all_rows: - - if row[10] is not None and row[11] is not None: - attachment_file = join(dirname(analyzed_file), 'Accounts/LocalAccount/Media', row[11], row[10]) - attachment_storage_path = dirname(attachment_file) - if imghdr.what(attachment_file) == 'jpeg' or imghdr.what(attachment_file) == 'jpg' or imghdr.what(attachment_file) == 'png': - thumbnail_path = join(report_folder, 'thumbnail_'+row[10]) - save_original_attachment_as_thumbnail(attachment_file, thumbnail_path) - thumbnail = ''.format(thumbnail_path) - else: - thumbnail = 'File is not an image or the filetype is not supported yet.' - else: - thumbnail = '' - attachment_storage_path = '' - - if row[12] is not None: - filesize = '.'.join(str(row[12])[i:i+3] for i in range(0, len(str(row[12])), 3)) - else: - filesize = '' - - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], thumbnail, row[10], attachment_storage_path, filesize, row[13], row[14], row[15])) - - report = ArtifactHtmlReport('Notes') - report.start_artifact_report(report_folder, 'Notes') - report.add_script() - data_headers = ('Creation Date', 'Note', 'Snippet', 'Folder', 'Storage Place', 'Last Modified', - 'Password Protected', 'Password Hint', 'Marked for Deletion', 'Pinned', 'Attachment Thumbnail', - 'Attachment Original Filename', 'Attachment Storage Folder', 'Attachment Size in KB', - 'Attachment Type', 'Attachment Creation Date', 'Attachment Last Modified') - report.write_artifact_data_table(data_headers, data_list, analyzed_file, html_no_escape=['Attachment Thumbnail']) - report.end_artifact_report() - - tsvname = 'Notes' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Notes' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Notes available') - - db.close() - return - - -def save_original_attachment_as_thumbnail(file, store_path): - image = Image.open(file) - thumbnail_max_size = (350, 350) - image.thumbnail(thumbnail_max_size) - image.save(store_path) diff --git a/scripts/artifacts/notificationsXI.py b/scripts/artifacts/notificationsXI.py deleted file mode 100644 index 5acc903b..00000000 --- a/scripts/artifacts/notificationsXI.py +++ /dev/null @@ -1,336 +0,0 @@ -import os -import textwrap -import datetime -import sys -import re -import string -import glob -from scripts.ccl import ccl_bplist -from html import escape - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, is_platform_windows - - -def get_notificationsXI(files_found, report_folder, seeker): - pathfound = 0 - count = 0 - notdircount = 0 - exportedbplistcount = 0 - unix = datetime.datetime(1970, 1, 1) # UTC - cocoa = datetime.datetime(2001, 1, 1) # UTC - delta = cocoa - unix - - __location__ = os.path.dirname(os.path.abspath(__file__)) - - f = open(os.path.join(__location__,"NotificationParams.txt"), "r") - notiparams = [line.strip() for line in f] - f.close() - - pathfound = str(files_found[0]) - #logfunc(pathfound) - if pathfound == 0: - logfunc("No PushStore directory located") - else: - #logfunc('Pathfound was found') - folder = report_folder - # logfunc("Processing:") - for filename in glob.iglob(pathfound + "/**", recursive=True): - if os.path.isfile(filename): # filter dirs - file_name = os.path.splitext(os.path.basename(filename))[0] - # get extension and iterate on those files - # file_extension = os.path.splitext(filename) - # logfunc(file_extension) - # create directory - if filename.endswith("pushstore"): - # create directory where script is running from - #logfunc(filename) # full path - notdircount = notdircount + 1 - # logfunc (os.path.basename(file_name)) #filename with no extension - openplist = os.path.basename( - os.path.normpath(filename) - ) # filename with extension - # logfunc (openplist) - # bundlepath = (os.path.basename(os.path.dirname(filename)))#previous directory - bundlepath = file_name - appdirect = folder + bundlepath - # logfunc(appdirect) - os.makedirs(appdirect) - - # open the plist - p = open(filename, "rb") - plist = ccl_bplist.load(p) - plist2 = plist["$objects"] - - long = len(plist2) - # logfunc (long) - h = open( - appdirect + "/DeliveredNotificationsReport.html", "w" - ) # write report - h.write("") - h.write("

iOS Delivered Notifications Triage Report

") - h.write(filename) - h.write("
") - h.write( - "" - ) - h.write("
") - - h.write('') - h.write('') - - f = open(os.path.join(__location__,"script.txt"), "r") - for line in f: - h.write(line) - f.close() - - h.write("
") - h.write('') - h.write('') - h.write("") - h.write("") - h.write("") - - h.write('') - h.write("") - h.write("") - h.write("") - - test = 0 - for i in range(0, long): - try: - if plist2[i]["$classes"]: - h.write('') - h.write("") - ob6 = str(plist2[i]["$classes"]) - h.write("") - h.write("") - test = 1 - except: - pass - try: - if plist2[i]["$class"]: - h.write('') - h.write("") - ob5 = str(plist2[i]["$class"]) - h.write("") - h.write("") - test = 1 - except: - pass - try: - if plist2[i]["NS.keys"]: - h.write('') - h.write("") - ob0 = str(plist2[i]["NS.keys"]) - h.write("") - h.write("") - test = 1 - except: - pass - try: - if plist2[i]["NS.objects"]: - ob1 = str(plist2[i]["NS.objects"]) - h.write('') - h.write("") - h.write("") - h.write("") - - test = 1 - except: - pass - try: - if plist2[i]["NS.time"]: - dia = str(plist2[i]["NS.time"]) - dias = dia.rsplit(".", 1)[0] - timestamp = ( - datetime.datetime.fromtimestamp(int(dias)) + delta - ) - # logfunc (timestamp) - - h.write("") - h.write("") - h.write("") - h.write("") - - test = 1 - except: - pass - try: - if plist2[i]["NS.base"]: - ob2 = str(plist2[i]["NS.objects"]) - h.write('') - h.write("") - h.write("") - h.write("") - - test = 1 - except: - pass - try: - if plist2[i]["$classname"]: - ob3 = str(plist2[i]["$classname"]) - h.write('') - h.write("") - h.write("") - h.write("") - - test = 1 - except: - pass - - try: - if test == 0: - if (plist2[i]) == "AppNotificationMessage": - h.write("
Data typeValue
PlistInitial Values
$classes") - h.write(str(ob6)) - h.write("
$class") - h.write(str(ob5)) - h.write("
NS.keys") - h.write(str(ob0)) - h.write("
NS.objects") - h.write(str(ob1)) - h.write("
Time UTC") - h.write(str(timestamp)) - # h.write(str(plist2[i]['NS.time'])) - h.write("
NS.base") - h.write(str(ob2)) - h.write("
$classname") - h.write(str(ob3)) - h.write("
") - h.write("
") - h.write("") - h.write("") - h.write("") - h.write("") - h.write("") - - h.write('') - h.write("") - h.write("") - h.write("") - - else: - if plist2[i] in notiparams: - h.write('') - h.write("") - h.write("") - h.write("") - elif plist2[i] == " ": - h.write('') - h.write("") - h.write("") - h.write("") - else: - h.write("") - h.write("") - h.write("") - h.write("") - - except: - pass - - test = 0 - - # h.write('test') - - for dict in plist2: - liste = dict - types = type(liste) - # logfunc (types) - try: - for k, v in liste.items(): - if k == "NS.data": - chk = str(v) - reduced = chk[2:8] - # logfunc (reduced) - if reduced == "bplist": - count = count + 1 - binfile = open( - "./" - + appdirect - + "/incepted" - + str(count) - + ".bplist", - "wb", - ) - binfile.write(v) - binfile.close() - - procfile = open( - "./" - + appdirect - + "/incepted" - + str(count) - + ".bplist", - "rb", - ) - secondplist = ccl_bplist.load(procfile) - secondplistint = secondplist["$objects"] - #logfunc("Bplist processed and exported.") - exportedbplistcount = exportedbplistcount + 1 - h.write('') - h.write("") - h.write("") - h.write("") - - procfile.close() - count = 0 - else: - h.write('') - h.write("") - h.write("") - h.write("") - except: - pass - h.close() - elif "AttachmentsList" in file_name: - test = 0 # future development - - path = report_folder - level2, level1 = (os.path.split(path)) - - #final = level2+'/'+level1 - dict = {} - files = os.listdir(path) - for name in files: - try: - size = os.path.getsize(f"{path}{name}/DeliveredNotificationsReport.html") - key = (f'{name}') - dict[key] = size - except NotADirectoryError as nade: - logfunc(nade) - pass - - - data_list = [] - for k, v in dict.items(): - v = v / 1000 - # logfunc(f'{k} -> {v}') - data_list.append((k, v)) - - location = pathfound - description = 'iOS <= 11 Notifications' - report = ArtifactHtmlReport('iOS Notificatons') - report.start_artifact_report(report_folder, 'iOS Notifications', description) - report.add_script() - data_headers = ('Bundle GUID', 'Reports Size') - report.write_artifact_data_table(data_headers, data_list, location, html_escape=False) - report.end_artifact_report() - - - logfunc("Total notification directories processed:" + str(notdircount)) - logfunc("Total exported bplists from notifications:" + str(exportedbplistcount)) - if notdircount == 0: - logfunc("No notifications located.") - - - - - - - \ No newline at end of file diff --git a/scripts/artifacts/notificationsXII.py b/scripts/artifacts/notificationsXII.py deleted file mode 100644 index e01f3dff..00000000 --- a/scripts/artifacts/notificationsXII.py +++ /dev/null @@ -1,104 +0,0 @@ -import os -import glob -import nska_deserialize as nd - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - -def get_bundle_id_and_names_from_plist(library_plist_file_path): - '''Parses Library.plist and returns a dictionary where Key=Bundle_ID, Value=Bundle_Name''' - bundle_info = {} - f = open(library_plist_file_path, 'rb') - plist = nd.deserialize_plist(f) - for k, v in plist.items(): - bundle_info[v] = k - f.close() - return bundle_info - -def get_bundle_info(files_found): - - for file_path in files_found: - file_path = str(file_path) - if file_path.endswith('Library.plist') and os.path.dirname(file_path).endswith('UserNotificationsServer'): - bundle_info = get_bundle_id_and_names_from_plist(file_path) - return bundle_info - # If this is fs search, then only top level folder will be present, so append path and search it too - if file_path.endswith('UserNotificationsServer'): - plist_file_path = os.path.join(file_path, 'Library.plist') - if os.path.exists(plist_file_path): - bundle_info = get_bundle_id_and_names_from_plist(plist_file_path) - return bundle_info - return {} - -def get_notificationsXII(files_found, report_folder, seeker): - - bundle_info = get_bundle_info(files_found) - data_list = [] - exportedbplistcount = 0 - - pathfound = str(files_found[0]) - # logfunc(f'Posix to string is: {pathfound}') - for filepath in glob.iglob(pathfound + "/**", recursive=True): - # create directory where script is running from - if os.path.isfile(filepath): # filter dirs - file_name = os.path.splitext(os.path.basename(filepath))[0] - # create directory - if filepath.endswith('DeliveredNotifications.plist'): - bundle_id = os.path.basename(os.path.dirname(filepath)) - # open the plist - p = open(filepath, "rb") - plist = nd.deserialize_plist(p) - - # Empty plist will be { 'root': None } - if isinstance(plist, dict): - continue # skip it, it's empty - - # Good plist will be a list of dicts - for item in plist: - creation_date = '' - title = '' - subtitle = '' - message = '' - other_dict = {} - bundle_name = bundle_info.get(bundle_id, bundle_id) - #if bundle_name == 'com.apple.ScreenTimeNotifications': - # pass # has embedded plist! - for k, v in item.items(): - if k == 'AppNotificationCreationDate': creation_date = str(v) - elif k == 'AppNotificationMessage': message = v - elif k == 'AppNotificationTitle': title = v - elif k == 'AppNotificationSubtitle': subtitle = v - else: - if isinstance(v, bytes): - logfunc(f'Found binary data, look into this one later k={k}!') - elif isinstance(v, dict): - pass # recurse look for plists #TODO - elif isinstance(v, list): - pass # recurse look for plists #TODO - other_dict[k] = str(v) - if subtitle: - title += f'[{subtitle}]' - data_list.append((creation_date, bundle_name, title, message, str(other_dict))) - p.close() - - elif "AttachmentsList" in file_name: - pass # future development - - description = 'iOS > 12 Notifications' - report = ArtifactHtmlReport('iOS Notificatons') - report.start_artifact_report(report_folder, 'iOS Notifications', description) - report.add_script() - data_headers = ('Creation Time', 'Bundle', 'Title[Subtitle]', 'Message', 'Other Details') - report.write_artifact_data_table(data_headers, data_list, filepath) - report.end_artifact_report() - - logfunc("Total notifications processed:" + str(len(data_list))) - #logfunc("Total exported bplists from notifications:" + str(exportedbplistcount)) - - tsvname = 'Notifications' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Notifications' - timeline(report_folder, tlactivity, data_list, data_headers) - if len(data_list) == 0: - logfunc("No notifications found.") diff --git a/scripts/artifacts/ooklaSpeedtestData.py b/scripts/artifacts/ooklaSpeedtestData.py deleted file mode 100644 index 7df1f157..00000000 --- a/scripts/artifacts/ooklaSpeedtestData.py +++ /dev/null @@ -1,174 +0,0 @@ -import glob -import os -import pathlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, kmlgen, is_platform_windows, open_sqlite_db_readonly - - -def get_ooklaSpeedtestData(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('speedtest.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - datetime(("ZDATE")+strftime('%s', '2001-01-01 00:00:00'), 'unixepoch') as 'Date', - "ZEXTERNALIP" as 'External IP Address', - "ZINTERNALIP" as 'Internal IP Address', - "ZCARRIERNAME" as 'Carrier Name', - "ZISP" as 'ISP', - "ZWIFISSID" as 'Wifi SSID', - "ZWANTYPE" as 'WAN Type', - CASE "ZDEVICEMODEL" - WHEN "iPad3,1" - THEN "iPad 3rd Gen (Wi-Fi Only)" - WHEN "iPad3,2" - THEN "iPad 3rd Gen (Wi-Fi/Cellular Verizon/GPS)" - WHEN "iPad3,3" - THEN "iPad 3rd Gen (Wi-Fi/Cellular AT&T/GPS)" - WHEN "iPad3,4" - THEN "iPad 4th Gen (Wi-Fi Only)" - WHEN "iPad3,5" - THEN "iPad 4th Gen (Wi-Fi/AT&T/GPS)" - WHEN "iPad3,6" - THEN "iPad 4th Gen (Wi-Fi/Verizon & Sprint/GPS)" - WHEN "iPad6,11" - THEN "iPad 9.7 5th Gen (Wi-Fi Only)" - WHEN "iPad6,12" - THEN "iPad 9.7 5th Gen (Wi-Fi/Cellular)" - WHEN "iPad7,5" - THEN "iPad 9.7 6th Gen (Wi-Fi Only)" - WHEN "iPad7,6" - THEN "iPad 9.7 6th Gen (Wi-Fi/Cellular)" - WHEN "iPad7,11" - THEN "iPad 10.2 7th Gen (Wi-Fi Only)" - WHEN "iPad7,12" - THEN "iPad 10.2 7th Gen (Wi-Fi/Cellular Global)" - WHEN "iPad11,3" - THEN "iPad Air 3rd Gen (Wi-Fi Only)" - WHEN "iPad11,4" - THEN "iPad Air 3rd Gen (Wi-Fi+Cell)" - WHEN "iPad2,5" - THEN "iPad mini Wi-Fi Only/1st Gen" - WHEN "iPad2,6" - THEN "iPad mini Wi-Fi/AT&T/GPS - 1st Gen" - WHEN "iPad2,7" - THEN "iPad mini Wi-Fi/VZ & Sprint/GPS - 1st Gen" - WHEN "iPad4,4" - THEN "iPad mini 2 (Retina/2nd Gen Wi-Fi Only)" - WHEN "iPad4,5" - THEN "iPad mini 2 (Retina/2nd Gen Wi-Fi/Cellular)" - WHEN "iPad4,7" - THEN "iPad mini 3 (Wi-Fi Only)" - WHEN "iPad4,8" - THEN "iPad mini 3 (Wi-Fi/Cellular)" - WHEN "iPad5,1" - THEN "iPad mini 4 (Wi-Fi Only)" - WHEN "iPad5,2" - THEN "iPad mini 4 (Wi-Fi/Cellular)" - WHEN "iPad11,1" - THEN "iPad mini 5th Gen (Wi-Fi Only)" - WHEN "iPad11,2" - THEN "iPad mini 5th Gen (Wi-Fi+Cell)" - WHEN "iPad6,7" - THEN "iPad Pro 12.9 (Wi-Fi Only)" - WHEN "iPad6,8" - THEN "iPad Pro 12.9 (Wi-Fi/Cellular)" - WHEN "iPad6,3" - THEN "iPad Pro 9.7 (Wi-Fi Only)" - WHEN "iPad6,4" - THEN "iPad Pro 9.7 (Wi-Fi/Cellular)" - WHEN "iPad7,3" - THEN "iPad Pro 10.5 (Wi-Fi Only)" - WHEN "iPad7,4" - THEN "iPad Pro 10.5 (Wi-Fi/Cellular)" - WHEN "iPad7,1" - THEN "iPad Pro 12.9 (Wi-Fi Only - 2nd Gen)" - WHEN "iPad7,2" - THEN "iPad Pro 12.9 (Wi-Fi/Cell - 2nd Gen)" - WHEN "iPad8,9" - THEN "iPad Pro 11 (Wi-Fi Only - 2nd Gen)" - WHEN "iPad8,10" - THEN "iPad Pro 11 (Wi-Fi/Cell - 2nd Gen)" - WHEN "iPad8,11" - THEN "iPad Pro 12.9 (Wi-Fi Only - 4th Gen)" - WHEN "iPad8,12" - THEN "iPad Pro 12.9 (Wi-Fi/Cell - 4th Gen)" - WHEN "iPhone8,4" - THEN "iPhone SE (United States/A1662)" - WHEN "iPhone9,1" - THEN "iPhone 7 (Verizon/Sprint/China/A1660)" - WHEN "iPhone9,3" - THEN "iPhone 7 (AT&T/T-Mobile/A1778)" - WHEN "iPhone9,2" - THEN "iPhone 7 Plus (Verizon/Sprint/China/A1661)" - WHEN "iPhone9,4" - THEN "iPhone 7 Plus (AT&T/T-Mobile/A1784)" - WHEN "iPhone10,1" - THEN "iPhone 8 (Verizon/Sprint/China/A1863)" - WHEN "iPhone10,4" - THEN "iPhone 8 (AT&T/T-Mobile/Global/A1905)" - WHEN "iPhone10,2" - THEN "iPhone 8 Plus (Verizon/Sprint/China/A1864)" - WHEN "iPhone10,5" - THEN "iPhone 8 Plus (AT&T/T-Mobile/Global/A1897)" - WHEN "iPhone10,3" - THEN "iPhone X (Verizon/Sprint/China/A1865)" - WHEN "iPhone10,6" - THEN "iPhone X (AT&T/T-Mobile/Global/A1901)" - WHEN "iPhone11,2" - THEN "iPhone Xs (A1920/A2097/A2098/A2100)" - WHEN "iPhone11,6" - THEN "iPhone Xs Max (A1921/A2101/A2101/A2104)" - WHEN "iPhone11,8" - THEN "iPhone XR (A1984/A2105/A2106/A2108)" - WHEN "iPhone12,1" - THEN "iPhone 11 (A2111/A2221/A2223)" - WHEN "iPhone12,3" - THEN "iPhone 11 Pro (A2160/A2215/A2217)" - WHEN "iPhone12,5" - THEN "iPhone 11 Pro Max (A2161/A2218/A2220)" - ELSE "ZDEVICEMODEL" - END 'Device Model', - "ZLATITUDE" as 'Latitude', - "ZLONGITUDE" as 'Longitude', - "ZHORIZONTALACCURACY" as 'Accuracy in Meters' - FROM ZSPEEDTESTRESULT - - ORDER BY "ZDATE" DESC - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10])) - - description = '' - report = ArtifactHtmlReport('Applications') - report.start_artifact_report(report_folder, 'Ookla Speedtest', description) - report.add_script() - data_headers = ('Timestamp','External IP Address','Internal IP Address','Carrier Name','ISP','Wifi SSID','WAN Type','Device Model','Latitude','Longitude','Accuracy in Meters' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Ookla Speedtest Data' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Ookla Speedtest Data' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Ookla Speedtest Data' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - else: - logfunc('No Ookla Speedtest Application data available') - - db.close() - return diff --git a/scripts/artifacts/photosMetadata.py b/scripts/artifacts/photosMetadata.py deleted file mode 100644 index 09fcd286..00000000 --- a/scripts/artifacts/photosMetadata.py +++ /dev/null @@ -1,1037 +0,0 @@ -import glob -import os -import sys -import stat -import pathlib -import sqlite3 -import nska_deserialize as nd -import scripts.artifacts.artGlobals -import shutil - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, kmlgen, timeline, is_platform_windows, generate_thumbnail, \ - open_sqlite_db_readonly - - -def get_photosMetadata(files_found, report_folder, seeker): - if report_folder.endswith('/') or report_folder.endswith('\\'): - report_folder = report_folder[:-1] - iOSversion = scripts.artifacts.artGlobals.versionf - if version.parse(iOSversion) < version.parse("12"): - logfunc("Unsupported version for Photos.sqlite metadata on iOS " + iOSversion) - if (version.parse(iOSversion) >= version.parse("12")) & (version.parse(iOSversion) < version.parse("13")): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - SELECT - DateTime( ZGENERICASSET.ZDATECREATED + 978307200, 'UNIXEPOCH' ) AS 'DateCreated', - ZGENERICASSET.Z_PK AS 'GenericAsset_zpk', - ZGENERICASSET.ZADDITIONALATTRIBUTES AS 'AddAttributes_Key', - ZDETECTEDFACE.ZASSET AS 'DetectedFaceAsset', - CASE - ZGENERICASSET.ZKIND - WHEN 0 THEN - 'Photo' - WHEN 1 THEN - 'Video' - END AS 'Kind', - ZADDITIONALASSETATTRIBUTES.ZEXIFTIMESTAMPSTRING AS 'EXIFtimestamp', - DateTime( ZADDITIONALASSETATTRIBUTES.ZSCENEANALYSISTIMESTAMP + 978307200, 'UNIXEPOCH' ) AS 'SceneAnalysisTimeStamp', - DateTime( ZGENERICASSET.ZADDEDDATE + 978307200, 'UNIXEPOCH' ) AS 'AddDate', - ZGENERICASSET.ZFILENAME AS 'FileName', - ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME AS 'OriginalFilename', - ZGENERICALBUM.ZTITLE AS 'AlbumTitle', - ZADDITIONALASSETATTRIBUTES.ZCREATORBUNDLEID AS 'CreatorBundleID', - ZADDITIONALASSETATTRIBUTES.ZEDITORBUNDLEID AS 'EditorBundleID', - ZGENERICASSET.ZDIRECTORY AS 'Directory', - ZGENERICASSET.ZUNIFORMTYPEIDENTIFIER AS 'UniformID', - CASE - ZGENERICASSET.ZSAVEDASSETTYPE - WHEN 0 THEN - 'Saved from other source' - WHEN 2 THEN - 'Photo Streams Data' - WHEN 3 THEN - 'Made/saved with this device' - WHEN 4 THEN - 'Default row' - WHEN 7 THEN - 'Deleted' ELSE ZGENERICASSET.ZSAVEDASSETTYPE - END AS 'SavedAssetType', - CASE - WHEN ZGENERICASSET.ZFACEAREAPOINTS > 0 THEN 'Yes' - ELSE 'NA' - END AS 'FaceDetectedinPhoto', - ZPERSON.ZDISPLAYNAME AS 'DisplayName', - ZPERSON.ZFULLNAME AS 'FullName', - ZPERSON.ZFACECOUNT AS 'FaceCount', - ZDETECTEDFACE.ZPERSON AS 'Person', - ZPERSON.ZCONTACTMATCHINGDICTIONARY AS 'ContactBlob', - ZPERSON.ZPERSONUUID as 'PersonUUID', - ZDETECTEDFACE.ZQUALITYMEASURE AS 'DetectedFaceQuality', - CASE - ZDETECTEDFACE.ZAGETYPE - WHEN 1 THEN - 'Baby/Toddler' - WHEN 2 THEN - 'Baby/Toddler' - WHEN 3 THEN - 'Child/YoungAdult' - WHEN 4 THEN - 'YoungAdult/Adult' - WHEN 5 THEN - 'Adult' - ELSE ZDETECTEDFACE.ZAGETYPE - END AS 'AgeTypeEstimate', - CASE - ZDETECTEDFACE.ZGENDERTYPE - WHEN 1 THEN - 'Male' - WHEN 2 THEN - 'Female' - ELSE ZDETECTEDFACE.ZGENDERTYPE - END AS 'Gender', - CASE - ZDETECTEDFACE.ZGLASSESTYPE - WHEN 3 THEN - 'None' - WHEN 2 THEN - 'Sun' - WHEN 1 THEN - 'Eye' - ELSE ZDETECTEDFACE.ZGLASSESTYPE - END AS 'GlassesType', - CASE - ZDETECTEDFACE.ZFACIALHAIRTYPE - WHEN 1 THEN - 'None' - WHEN 2 THEN - 'Beard/Mustache' - WHEN 3 THEN - 'Goatee' - WHEN 5 THEN - 'Stubble' - ELSE ZDETECTEDFACE.ZFACIALHAIRTYPE - END AS 'FacialHairType', - CASE - ZDETECTEDFACE.ZBALDTYPE - WHEN 2 THEN - 'Bald' - WHEN 3 THEN - 'NotBald' - ELSE ZDETECTEDFACE.ZBALDTYPE - END AS 'Baldness', - ZGENERICASSET.ZORIGINALCOLORSPACE AS 'ColorSpace', - ZGENERICASSET.Zduration AS 'Duration', - ZGENERICASSET.Zvideocpdurationvalue AS 'VideoDuration', - CASE - ZGENERICASSET.ZCOMPLETE - WHEN 1 THEN - 'Yes' - END AS 'Complete', - CASE - ZGENERICASSET.ZVISIBILITYSTATE - WHEN 0 THEN - 'Visible' - WHEN 1 THEN - 'Photo Streams Data' - WHEN 2 THEN - 'Burst' ELSE ZVISIBILITYSTATE - END AS 'VisibilityState', - CASE - ZGENERICASSET.ZFAVORITE - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'Favorite', - CASE - ZGENERICASSET.zhidden - WHEN 0 THEN - 'Not_Hidden' - WHEN 1 THEN - 'File_Hidden' ELSE ZGENERICASSET.zhidden - END AS 'Hidden_File', - CASE - ZGENERICASSET.ZTRASHEDSTATE - WHEN 1 THEN - 'In_Trash' - WHEN 0 THEN - 'Not_In_Trash' ELSE ZGENERICASSET.ZTRASHEDSTATE - END AS 'TrashState', - DateTime( ZGENERICASSET.ZTRASHEDDATE + 978307200, 'UNIXEPOCH' ) AS 'FileTrashDate', - ZADDITIONALASSETATTRIBUTES.ZVIEWCOUNT AS 'ViewCount', - ZADDITIONALASSETATTRIBUTES.ZPLAYCOUNT AS 'PlayCount', - ZADDITIONALASSETATTRIBUTES.ZSHARECOUNT AS 'ShareCount', - DateTime( ZGENERICASSET.ZLASTSHAREDDATE + 978307200, 'UNIXEPOCH' ) AS 'LastSharedDate', - DateTime( ZGENERICASSET.ZMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'FileModificationDate', - CASE - ZGENERICASSET.ZHASADJUSTMENTS - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'Has_Adjustments', - DateTime( ZGENERICASSET.ZADJUSTMENTTIMESTAMP + 978307200, 'UNIXEPOCH' ) AS 'AdjustmentsTimeStamp', - ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE AS 'OriginalFileSize', - ZGENERICASSET.ZHEIGHT AS 'File_Height', - ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT AS 'OrgFileHeight', - ZGENERICASSET.ZWIDTH AS 'File_Width', - ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH AS 'OrgFileWidth', - CASE - ZGENERICASSET.ZORIENTATION - WHEN 1 THEN - 'Horizontal (left)' - WHEN 3 THEN - 'Horizontal (right)' - WHEN 6 THEN - 'Vertical (up)' - WHEN 8 THEN - 'Vertical (down)' ELSE ZORIENTATION - END AS 'Orientation', - CASE - ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION - WHEN 1 THEN - 'Horizontal (left)' - WHEN 3 THEN - 'Horizontal (right)' - WHEN 6 THEN - 'Vertical (up)' - WHEN 8 THEN - 'Vertical (down)' ELSE ZORIENTATION - END AS 'Org_Orientation', - ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME AS 'TimeZoneName', - ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET AS 'TimeZoneOffset', - ZGENERICASSET.ZLOCATIONDATA AS 'FileLocationData', - CASE - ZGENERICASSET.ZLATITUDE - WHEN - 180.0 THEN - '' ELSE ZGENERICASSET.ZLATITUDE - END AS 'Latitude', - CASE - ZGENERICASSET.ZLONGITUDE - WHEN - 180.0 THEN - '' ELSE ZGENERICASSET.ZLONGITUDE - END AS 'Longitude', - CASE - ZADDITIONALASSETATTRIBUTES.ZSHIFTEDLOCATIONISVALID - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'ShiftedLocationValid', - CASE - ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATAISVALID - WHEN 0 THEN - 'No_Check_SceneAnalysis' - WHEN 1 THEN - 'Yes_Check_SceneAnalysis' - END AS 'ReverseLocationDataIsValid', - ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA AS 'OrgFileReverseLocationData', - ZGENERICASSET.Zthumbnailindex AS 'ThumbnailIndex', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILWIDTH AS 'EmbeddedThumbnailWidth', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILHEIGHT AS 'EmbeddedThumbnailHeight', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILOFFSET AS 'EmbeddedThumbnailOffset', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILLENGTH AS 'EmbeddedThumbnailLenght', - ZGENERICASSET.ZMOMENT AS 'MomentPK', - DateTime( ZMOMENT.ZSTARTDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentStartDate', - DateTime( ZMOMENT.Zrepresentativedate + 978307200, 'UNIXEPOCH' ) AS 'MomentRepresentativeDate', - DateTime( ZMOMENT.ZMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentModificationDate', - DateTime( ZMOMENT.ZENDDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentEndDate', - ZMOMENT.ZTITLE AS 'MomentTitle', - CASE - ZMOMENT.Zapproximatelatitude - WHEN - 180.0 THEN - '' ELSE ZMOMENT.Zapproximatelatitude - END AS 'MomentApproxLatitude', - CASE - ZMOMENT.Zapproximatelongitude - WHEN - 180.0 THEN - '' ELSE ZMOMENT.Zapproximatelongitude - END AS 'MomentApproxLongitude', - ZGENERICASSET.ZUUID AS 'UUID', - ZGENERICASSET.ZMEDIAGROUPUUID AS 'MediaGroupUUID', - ZGENERICASSET.ZCLOUDASSETGUID AS 'CloudAssetGUID', - ZADDITIONALASSETATTRIBUTES.ZPUBLICGLOBALUUID AS 'PublicGlobalUUID', - ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT AS 'MasterFingerprint', - ZADDITIONALASSETATTRIBUTES.ZADJUSTEDFINGERPRINT AS 'AdjustedFingerprint' - FROM - ZGENERICASSET - JOIN Z_PRIMARYKEY ON ZGENERICASSET.z_ent = Z_PRIMARYKEY.z_ent - LEFT JOIN ZMOMENT ON ZGENERICASSET.ZMOMENT = ZMOMENT.Z_PK - JOIN ZADDITIONALASSETATTRIBUTES ON ZGENERICASSET.ZADDITIONALATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK - LEFT JOIN ZDETECTEDFACE ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZDETECTEDFACE.ZASSET - LEFT JOIN ZPERSON ON ZPERSON.Z_PK = ZDETECTEDFACE.ZPERSON - LEFT JOIN Z_23ASSETS ON ZGENERICASSET.Z_PK = Z_23ASSETS.Z_30ASSETS - LEFT JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_23ASSETS.Z_23ALBUMS - - """) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - counter = 0 - if usageentries > 0: - for row in all_rows: - postal_address = '' - postal_address_subadminarea = '' - postal_address_sublocality = '' - - if row[59] is not None: - pathto = os.path.join(report_folder, 'ReverseLocationData' + str(counter) + '.bplist') - with open(pathto, 'ab') as wf: - wf.write(row[59]) - - with open(pathto, 'rb') as f: - try: - deserialized_plist = nd.deserialize_plist(f) - postal_address = deserialized_plist['postalAddress']['_formattedAddress'] - postal_address_subadminarea = deserialized_plist['postalAddress']['_subAdministrativeArea'] - postal_address_sublocality = deserialized_plist['postalAddress']['_subLocality'] - - except (KeyError, ValueError, TypeError) as ex: - if str(ex).find("does not contain an '$archiver' key") >= 0: - logfunc('plist was Not an NSKeyedArchive ' + row[0]) - else: - logfunc('Error reading exported bplist from Asset PK ' + row[0]) - deserialized_plist = None - - htmlThumbTag = generate_thumbnail(row[13], row[8], seeker, report_folder) - - - data_list.append((htmlThumbTag, row[0], row[0], postal_address, postal_address_subadminarea, - postal_address_sublocality, row[1], row[2], row[3], row[4], row[5], row[6], row[7], - row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], - row[17], row[18], row[19], row[20], row[21], row[22], row[23], row[24], row[25], - row[26], row[27], row[28], row[29], row[30], row[31], row[32], row[33], row[34], - row[35], row[36], row[37], row[38], row[39], row[40], row[41], row[42], row[43], - row[44], row[45], row[46], row[47], row[48], row[49], row[50], row[51], row[52], - row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60], row[61], - row[62], row[63], row[64], row[65], row[66], row[67], row[68], row[69], row[70], - row[71], row[72], row[73], row[74], row[75], row[76], row[77], row[78])) - - counter += 1 - - description = '' - report = ArtifactHtmlReport('Photos.sqlite') - report.start_artifact_report(report_folder, 'Metadata', description) - report.add_script() - data_headers = ( - 'Thumbnail', 'Timestamp', 'Date Created', 'Postal Address', 'Postal Subadmin Area', - 'Postal Sublocality', - 'Generic Asset ZPK', 'Add Attributes Key', 'Detected Face Asset', 'Kind', 'EXIF Timestamp', - 'Scene Analysis Timestamp', 'Add Date', 'Filename', 'Original Filename', 'Album Title', - 'Creator Bundle ID', - 'Editor Bundle ID', 'Directory', 'Uniform ID', 'Saved Asset Type', 'Face Detected in Photo', - 'Display Name', - 'Full Name', 'Face Count', 'Person', 'Contact Blob', 'Person UUID', 'Detected Face Quality', - 'Age Type Estimate', 'Gender', 'Glasses Type', 'Facial Hair Type', 'Baldness', 'Color Space', - 'Duration', - 'Video Duration', 'Complete', 'Visibility State', 'Favorite', 'Hidden File?', 'Trash State', - 'File Trash Date', 'View Count', 'Play Count', 'Share Count', 'Last Shared Date', - 'File Modification Date', - 'Has Adjustments?', 'Adjustment Timestamp', 'Original File Size', 'File Height', 'Org File Height', - 'File Width', 'Org File Width', 'Orientation', 'Org Orientation', 'Timezone Name', 'Timezone Offset', - 'File Location Data', 'Latitude', 'Longitude', 'Shifted Location Valid', - 'Reverse Location Data is Valid', - 'Org File Reverse Location Data', 'Thumbnail Index', 'Embedded Thumbnail Width', - 'Embedded Thumbnail Height', 'Embedded Thumbnail Offset', 'Embedded Thumbnail Lenght', 'Moment PK', - 'Moment Start Date', 'Moment Representative Date', 'Moment Modification Date', 'Moment End Date', - 'Moment Title', 'Moment Approx Latitude', 'Moment Approx Longitude', 'UUID', 'Media Group UUID', - 'Cloud Assest GUID', 'Public Global UUID', 'Master Fingetprint', 'Adjusted Fingerprint') - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Thumbnail']) - report.end_artifact_report() - - tsvname = 'Photos-sqlite Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Photos-sqlite Metadata' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Photos-sqlite Metadata' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - else: - logfunc('No data available for Photos.sqlite metadata') - - db.close() - return - - elif (version.parse(iOSversion) >= version.parse("13")) & (version.parse(iOSversion) < version.parse("14")): - file_found = str(files_found[0]) - # os.chmod(file_found, 0o0777) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - SELECT - DateTime( ZGENERICASSET.ZDATECREATED + 978307200, 'UNIXEPOCH' ) AS 'DateCreated', - ZGENERICASSET.Z_PK AS 'GenericAsset_zpk', - ZGENERICASSET.ZADDITIONALATTRIBUTES AS 'AddAttributes_Key', - ZDETECTEDFACE.ZASSET AS 'DetectedFaceAsset', - CASE - ZGENERICASSET.ZKIND - WHEN 0 THEN - 'Photo' - WHEN 1 THEN - 'Video' - END AS 'Kind', - ZADDITIONALASSETATTRIBUTES.ZEXIFTIMESTAMPSTRING AS 'EXIFtimestamp', - DateTime( ZADDITIONALASSETATTRIBUTES.ZSCENEANALYSISTIMESTAMP + 978307200, 'UNIXEPOCH' ) AS 'SceneAnalysisTimeStamp', - DateTime( ZGENERICASSET.ZANALYSISSTATEMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'AnalysisStateModificationDate', - DateTime( ZGENERICASSET.ZADDEDDATE + 978307200, 'UNIXEPOCH' ) AS 'AddDate', - ZGENERICASSET.ZFILENAME AS 'FileName', - ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME AS 'OriginalFilename', - ZGENERICALBUM.ZTITLE AS 'AlbumTitle', - ZADDITIONALASSETATTRIBUTES.ZCREATORBUNDLEID AS 'CreatorBundleID', - ZADDITIONALASSETATTRIBUTES.ZEDITORBUNDLEID AS 'EditorBundleID', - ZGENERICASSET.ZDIRECTORY AS 'Directory', - ZGENERICASSET.ZUNIFORMTYPEIDENTIFIER AS 'UniformID', - CASE - ZGENERICASSET.ZSAVEDASSETTYPE - WHEN 0 THEN - 'Saved from other source' - WHEN 2 THEN - 'Photo Streams Data' - WHEN 3 THEN - 'Made/saved with this device' - WHEN 4 THEN - 'Default row' - WHEN 7 THEN - 'Deleted' ELSE ZGENERICASSET.ZSAVEDASSETTYPE - END AS 'SavedAssetType', - CASE - WHEN ZGENERICASSET.ZFACEAREAPOINTS > 0 THEN 'Yes' - ELSE 'NA' - END AS 'FaceDetectedinPhoto', - ZPERSON.ZDISPLAYNAME AS 'DisplayName', - ZPERSON.ZFULLNAME AS 'FullName', - ZPERSON.ZFACECOUNT AS 'FaceCount', - ZDETECTEDFACE.ZPERSON AS 'Person', - ZPERSON.ZCONTACTMATCHINGDICTIONARY AS 'ContactBlob', - ZPERSON.ZPERSONUUID as 'PersonUUID', - ZDETECTEDFACE.ZQUALITYMEASURE AS 'DetectedFaceQuality', - CASE - ZDETECTEDFACE.ZAGETYPE - WHEN 1 THEN - 'Baby/Toddler' - WHEN 2 THEN - 'Baby/Toddler' - WHEN 3 THEN - 'Child/YoungAdult' - WHEN 4 THEN - 'YoungAdult/Adult' - WHEN 5 THEN - 'Adult' - ELSE ZDETECTEDFACE.ZAGETYPE - END AS 'AgeTypeEstimate', - CASE - ZDETECTEDFACE.ZGENDERTYPE - WHEN 1 THEN - 'Male' - WHEN 2 THEN - 'Female' - ELSE ZDETECTEDFACE.ZGENDERTYPE - END AS 'Gender', - CASE - ZDETECTEDFACE.ZGLASSESTYPE - WHEN 3 THEN - 'None' - WHEN 2 THEN - 'Sun' - WHEN 1 THEN - 'Eye' - ELSE ZDETECTEDFACE.ZGLASSESTYPE - END AS 'GlassesType', - CASE - ZDETECTEDFACE.ZFACIALHAIRTYPE - WHEN 1 THEN - 'None' - WHEN 2 THEN - 'Beard/Mustache' - WHEN 3 THEN - 'Goatee' - WHEN 5 THEN - 'Stubble' - ELSE ZDETECTEDFACE.ZFACIALHAIRTYPE - END AS 'FacialHairType', - CASE - ZDETECTEDFACE.ZBALDTYPE - WHEN 2 THEN - 'Bald' - WHEN 3 THEN - 'NotBald' - ELSE ZDETECTEDFACE.ZBALDTYPE - END AS 'Baldness', - ZGENERICASSET.ZORIGINALCOLORSPACE AS 'ColorSpace', - ZGENERICASSET.Zduration AS 'Duration', - ZGENERICASSET.Zvideocpdurationvalue AS 'VideoDuration', - CASE - ZGENERICASSET.ZCOMPLETE - WHEN 1 THEN - 'Yes' - END AS 'Complete', - CASE - ZGENERICASSET.ZVISIBILITYSTATE - WHEN 0 THEN - 'Visible' - WHEN 1 THEN - 'Photo Streams Data' - WHEN 2 THEN - 'Burst' ELSE ZVISIBILITYSTATE - END AS 'VisibilityState', - CASE - ZGENERICASSET.ZFAVORITE - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'Favorite', - CASE - ZGENERICASSET.zhidden - WHEN 0 THEN - 'Not_Hidden' - WHEN 1 THEN - 'File_Hidden' ELSE ZGENERICASSET.zhidden - END AS 'Hidden_File', - CASE - ZGENERICASSET.ZTRASHEDSTATE - WHEN 1 THEN - 'In_Trash' - WHEN 0 THEN - 'Not_In_Trash' ELSE ZGENERICASSET.ZTRASHEDSTATE - END AS 'TrashState', - DateTime( ZGENERICASSET.ZTRASHEDDATE + 978307200, 'UNIXEPOCH' ) AS 'FileTrashDate', - ZADDITIONALASSETATTRIBUTES.ZVIEWCOUNT AS 'ViewCount', - ZADDITIONALASSETATTRIBUTES.ZPLAYCOUNT AS 'PlayCount', - ZADDITIONALASSETATTRIBUTES.ZSHARECOUNT AS 'ShareCount', - DateTime( ZGENERICASSET.ZLASTSHAREDDATE + 978307200, 'UNIXEPOCH' ) AS 'LastSharedDate', - DateTime( ZGENERICASSET.ZMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'FileModificationDate', - CASE - ZGENERICASSET.ZHASADJUSTMENTS - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'Has_Adjustments', - DateTime( ZGENERICASSET.ZADJUSTMENTTIMESTAMP + 978307200, 'UNIXEPOCH' ) AS 'AdjustmentsTimeStamp', - ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE AS 'OriginalFileSize', - ZGENERICASSET.ZHEIGHT AS 'File_Height', - ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT AS 'OrgFileHeight', - ZGENERICASSET.ZWIDTH AS 'File_Width', - ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH AS 'OrgFileWidth', - CASE - ZGENERICASSET.ZORIENTATION - WHEN 1 THEN - 'Horizontal (left)' - WHEN 3 THEN - 'Horizontal (right)' - WHEN 6 THEN - 'Vertical (up)' - WHEN 8 THEN - 'Vertical (down)' ELSE ZORIENTATION - END AS 'Orientation', - CASE - ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION - WHEN 1 THEN - 'Horizontal (left)' - WHEN 3 THEN - 'Horizontal (right)' - WHEN 6 THEN - 'Vertical (up)' - WHEN 8 THEN - 'Vertical (down)' ELSE ZORIENTATION - END AS 'Org_Orientation', - ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME AS 'TimeZoneName', - ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET AS 'TimeZoneOffset', - ZADDITIONALASSETATTRIBUTES.ZINFERREDTIMEZONEOFFSET AS 'InferredTimeZoneOffset', - ZGENERICASSET.ZLOCATIONDATA AS 'FileLocationData', - CASE - ZGENERICASSET.ZLATITUDE - WHEN - 180.0 THEN - '' ELSE ZGENERICASSET.ZLATITUDE - END AS 'Latitude', - CASE - ZGENERICASSET.ZLONGITUDE - WHEN - 180.0 THEN - '' ELSE ZGENERICASSET.ZLONGITUDE - END AS 'Longitude', - CASE - ZADDITIONALASSETATTRIBUTES.ZSHIFTEDLOCATIONISVALID - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'ShiftedLocationValid', - CASE - ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATAISVALID - WHEN 0 THEN - 'No_Check_SceneAnalysis' - WHEN 1 THEN - 'Yes_Check_SceneAnalysis' - END AS 'ReverseLocationDataIsValid', - ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA AS 'OrgFileReverseLocationData', - ZGENERICASSET.Zthumbnailindex AS 'ThumbnailIndex', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILWIDTH AS 'EmbeddedThumbnailWidth', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILHEIGHT AS 'EmbeddedThumbnailHeight', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILOFFSET AS 'EmbeddedThumbnailOffset', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILLENGTH AS 'EmbeddedThumbnailLenght', - ZGENERICASSET.ZMOMENT AS 'MomentPK', - DateTime( ZMOMENT.ZSTARTDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentStartDate', - DateTime( ZMOMENT.Zrepresentativedate + 978307200, 'UNIXEPOCH' ) AS 'MomentRepresentativeDate', - DateTime( ZMOMENT.ZMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentModificationDate', - DateTime( ZMOMENT.ZENDDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentEndDate', - ZMOMENT.ZTITLE AS 'MomentTitle', - CASE - ZMOMENT.Zapproximatelatitude - WHEN - 180.0 THEN - '' ELSE ZMOMENT.Zapproximatelatitude - END AS 'MomentApproxLatitude', - CASE - ZMOMENT.Zapproximatelongitude - WHEN - 180.0 THEN - '' ELSE ZMOMENT.Zapproximatelongitude - END AS 'MomentApproxLongitude', - ZGENERICASSET.ZUUID AS 'UUID', - ZGENERICASSET.ZMEDIAGROUPUUID AS 'MediaGroupUUID', - ZGENERICASSET.ZCLOUDASSETGUID AS 'CloudAssetGUID', - ZADDITIONALASSETATTRIBUTES.ZPUBLICGLOBALUUID AS 'PublicGlobalUUID', - ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT AS 'MasterFingerprint', - ZADDITIONALASSETATTRIBUTES.ZADJUSTEDFINGERPRINT AS 'AdjustedFingerprint' - FROM - ZGENERICASSET - JOIN Z_PRIMARYKEY ON ZGENERICASSET.z_ent = Z_PRIMARYKEY.z_ent - LEFT JOIN ZMOMENT ON ZGENERICASSET.ZMOMENT = ZMOMENT.Z_PK - JOIN ZADDITIONALASSETATTRIBUTES ON ZGENERICASSET.ZADDITIONALATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK - LEFT JOIN ZDETECTEDFACE ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZDETECTEDFACE.ZASSET - LEFT JOIN ZPERSON ON ZPERSON.Z_PK = ZDETECTEDFACE.ZPERSON - LEFT JOIN Z_26ASSETS ON ZGENERICASSET.Z_PK = Z_26ASSETS.Z_34ASSETS - LEFT JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - counter = 0 - if usageentries > 0: - for row in all_rows: - postal_address = '' - postal_address_subadminarea = '' - postal_address_sublocality = '' - - if row[61] is not None: - pathto = os.path.join(report_folder, 'ReverseLocationData' + str(counter) + '.bplist') - with open(pathto, 'ab') as wf: - wf.write(row[61]) - - with open(pathto, 'rb') as f: - try: - deserialized_plist = nd.deserialize_plist(f) - postal_address = deserialized_plist['postalAddress']['_formattedAddress'] - postal_address_subadminarea = deserialized_plist['postalAddress']['_subAdministrativeArea'] - postal_address_sublocality = deserialized_plist['postalAddress']['_subLocality'] - - except: - logfunc('Error reading exported bplist from Asset PK' + row[0]) - deserialized_plist = None - - htmlThumbTag = generate_thumbnail(row[14], row[9], seeker, report_folder) - - data_list.append((htmlThumbTag, row[0], row[0], postal_address, postal_address_subadminarea, - postal_address_sublocality, row[1], row[2], row[3], row[4], row[5], row[6], row[7], - row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], - row[17], row[18], row[19], row[20], row[21], row[22], row[23], row[24], row[25], - row[26], row[27], row[28], row[29], row[30], row[31], row[32], row[33], row[34], - row[35], row[36], row[37], row[38], row[39], row[40], row[41], row[42], row[43], - row[44], row[45], row[46], row[47], row[48], row[49], row[50], row[51], row[52], - row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60], row[61], - row[62], row[63], row[64], row[65], row[66], row[67], row[68], row[69], row[70], - row[71], row[72], row[73], row[74], row[75], row[76], row[77], row[78], row[79], - row[80])) - - counter += 1 - - description = '' - report = ArtifactHtmlReport('Photos.sqlite') - report.start_artifact_report(report_folder, 'Metadata', description) - report.add_script() - data_headers = ( - 'Thumbnail', 'Timestamp', 'Date Created', 'Postal Address', 'Postal Subadmin Area', - 'Postal Sublocality', - 'Generic Asset ZPK', 'Add Attributes Key', 'Detected Face Asset', 'Kind', 'EXIF Timestamp', - 'Scene Analysis Timestamp', 'Analysis State Modified Date', 'Add Date', 'Filename', 'Original Filename', - 'Album Title', 'Creator Bundle ID', 'Editor Bundle ID', 'Directory', 'Uniform ID', 'Saved Asset Type', - 'Face Detected in Photo', 'Display Name', 'Full Name', 'Face Count', 'Person', 'Contact Blob', - 'Person UUID', 'Detected Face Quality', 'Age Type Estimate', 'Gender', 'Glasses Type', - 'Facial Hair Type', - 'Baldness', 'Color Space', 'Duration', 'Video Duration', 'Complete', 'Visibility State', 'Favorite', - 'Hidden File?', 'Trash State', 'File Trash Date', 'View Count', 'Play Count', 'Share Count', - 'Last Shared Date', 'File Modification Date', 'Has Adjustments?', 'Adjustment Timestamp', - 'Original File Size', 'File Height', 'Org File Height', 'File Width', 'Org File Width', 'Orientation', - 'Org Orientation', 'Timezone Name', 'Timezone Offset', 'Infered Timezone Offset', 'File Location Data', - 'Latitude', 'Longitude', 'Shifted Location Valid', 'Reverse Location Data is Valid', - 'Org File Reverse Location Data', 'Thumbnail Index', 'Embedded Thumbnail Width', - 'Embedded Thumbnail Height', 'Embedded Thumbnail Offset', 'Embedded Thumbnail Lenght', 'Moment PK', - 'Moment Start Date', 'Moment Representative Date', 'Moment Modification Date', 'Moment End Date', - 'Moment Title', 'Moment Approx Latitude', 'Moment Approx Longitude', 'UUID', 'Media Group UUID', - 'Cloud Assest GUID', 'Public Global UUID', 'Master Fingetprint', 'Adjusted Fingerprint') - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Thumbnail']) - report.end_artifact_report() - - tsvname = 'Photos-sqlite Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Photos-sqlite Metadata' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Photos-sqlite Metadata' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - else: - logfunc('No data available for Photos.sqlite metadata') - - db.close() - return - elif version.parse(iOSversion) >= version.parse("14"): - file_found = str(files_found[0]) - # os.chmod(file_found, 0o0777) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - SELECT - - DateTime( ZASSET.ZDATECREATED + 978307200, 'UNIXEPOCH' ) AS 'DateCreated', - ZASSET.Z_PK AS 'Asset_zpk', - ZASSET.ZADDITIONALATTRIBUTES AS 'AddAttributes_Key', - ZDETECTEDFACE.ZASSET AS 'DetectedFaceAsset', - CASE - ZASSET.ZKIND - WHEN 0 THEN - 'Photo' - WHEN 1 THEN - 'Video' - END AS 'Kind', - - ZADDITIONALASSETATTRIBUTES.ZEXIFTIMESTAMPSTRING AS 'EXIFtimestamp', - DateTime( ZADDITIONALASSETATTRIBUTES.ZSCENEANALYSISTIMESTAMP + 978307200, 'UNIXEPOCH' ) AS 'SceneAnalysisTimeStamp', - DateTime( ZASSET.ZANALYSISSTATEMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'AnalysisStateModificationDate', - DateTime( ZASSET.ZADDEDDATE + 978307200, 'UNIXEPOCH' ) AS 'AddDate', - ZASSET.ZFILENAME AS 'FileName', - ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME AS 'OriginalFilename', - ZGENERICALBUM.ZTITLE AS 'AlbumTitle', - ZADDITIONALASSETATTRIBUTES.ZCREATORBUNDLEID AS 'CreatorBundleID', - ZADDITIONALASSETATTRIBUTES.ZEDITORBUNDLEID AS 'EditorBundleID', - ZASSET.ZDIRECTORY AS 'Directory', - ZASSET.ZUNIFORMTYPEIDENTIFIER AS 'UniformID', - CASE - ZASSET.ZSAVEDASSETTYPE - WHEN 0 THEN - 'Saved from other source' - WHEN 2 THEN - 'Photo Streams Data' - WHEN 3 THEN - 'Made/saved with this device' - WHEN 4 THEN - 'Default row' - WHEN 7 THEN - 'Deleted' ELSE ZASSET.ZSAVEDASSETTYPE - END AS 'SavedAssetType', - CASE - WHEN ZASSET.ZFACEAREAPOINTS > 0 THEN 'Yes' - ELSE 'NA' - END AS 'FaceDetectedinPhoto', - ZPERSON.ZDISPLAYNAME AS 'DisplayName', - ZPERSON.ZFULLNAME AS 'FullName', - ZPERSON.ZFACECOUNT AS 'FaceCount', - ZDETECTEDFACE.ZPERSON AS 'Person', - ZPERSON.ZCONTACTMATCHINGDICTIONARY AS 'ContactBlob', - ZPERSON.ZPERSONUUID as 'PersonUUID', - ZDETECTEDFACE.ZQUALITYMEASURE AS 'DetectedFaceQuality', - CASE - ZDETECTEDFACE.ZAGETYPE - WHEN 1 THEN - 'Baby/Toddler' - WHEN 2 THEN - 'Baby/Toddler' - WHEN 3 THEN - 'Child/YoungAdult' - WHEN 4 THEN - 'YoungAdult/Adult' - WHEN 5 THEN - 'Adult' - ELSE ZDETECTEDFACE.ZAGETYPE - END AS 'AgeTypeEstimate', - CASE - ZDETECTEDFACE.ZGENDERTYPE - WHEN 1 THEN - 'Male' - WHEN 2 THEN - 'Female' - ELSE ZDETECTEDFACE.ZGENDERTYPE - END AS 'Gender', - CASE - ZDETECTEDFACE.ZGLASSESTYPE - WHEN 3 THEN - 'None' - WHEN 2 THEN - 'Sun' - WHEN 1 THEN - 'Eye' - ELSE ZDETECTEDFACE.ZGLASSESTYPE - END AS 'GlassesType', - CASE - ZDETECTEDFACE.ZFACIALHAIRTYPE - WHEN 1 THEN - 'None' - WHEN 2 THEN - 'Beard/Mustache' - WHEN 3 THEN - 'Goatee' - WHEN 5 THEN - 'Stubble' - ELSE ZDETECTEDFACE.ZFACIALHAIRTYPE - END AS 'FacialHairType', - CASE - ZDETECTEDFACE.ZBALDTYPE - WHEN 2 THEN - 'Bald' - WHEN 3 THEN - 'NotBald' - ELSE ZDETECTEDFACE.ZBALDTYPE - END AS 'Baldness', - ZASSET.ZORIGINALCOLORSPACE AS 'ColorSpace', - ZASSET.Zduration AS 'Duration', - ZASSET.Zvideocpdurationvalue AS 'VideoDuration', - CASE - ZASSET.ZCOMPLETE - WHEN 1 THEN - 'Yes' - END AS 'Complete', - CASE - ZASSET.ZVISIBILITYSTATE - WHEN 0 THEN - 'Visible' - WHEN 1 THEN - 'Photo Streams Data' - WHEN 2 THEN - 'Burst' ELSE ZVISIBILITYSTATE - END AS 'VisibilityState', - CASE - ZASSET.ZFAVORITE - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'Favorite', - CASE - ZASSET.zhidden - WHEN 0 THEN - 'Not_Hidden' - WHEN 1 THEN - 'File_Hidden' ELSE ZASSET.zhidden - END AS 'Hidden_File', - CASE - ZASSET.ZTRASHEDSTATE - WHEN 1 THEN - 'In_Trash' - WHEN 0 THEN - 'Not_In_Trash' ELSE ZASSET.ZTRASHEDSTATE - END AS 'TrashState', - DateTime( ZASSET.ZTRASHEDDATE + 978307200, 'UNIXEPOCH' ) AS 'FileTrashDate', - ZADDITIONALASSETATTRIBUTES.ZVIEWCOUNT AS 'ViewCount', - ZADDITIONALASSETATTRIBUTES.ZPLAYCOUNT AS 'PlayCount', - ZADDITIONALASSETATTRIBUTES.ZSHARECOUNT AS 'ShareCount', - DateTime( ZASSET.ZLASTSHAREDDATE + 978307200, 'UNIXEPOCH' ) AS 'LastSharedDate', - DateTime( ZASSET.ZMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'FileModificationDate', - CASE - ZASSET.ZHASADJUSTMENTS - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'Has_Adjustments', - DateTime( ZASSET.ZADJUSTMENTTIMESTAMP + 978307200, 'UNIXEPOCH' ) AS 'AdjustmentsTimeStamp', - ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE AS 'OriginalFileSize', - ZASSET.ZHEIGHT AS 'File_Height', - ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT AS 'OrgFileHeight', - ZASSET.ZWIDTH AS 'File_Width', - ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH AS 'OrgFileWidth', - CASE - ZASSET.ZORIENTATION - WHEN 1 THEN - 'Horizontal (left)' - WHEN 3 THEN - 'Horizontal (right)' - WHEN 6 THEN - 'Vertical (up)' - WHEN 8 THEN - 'Vertical (down)' ELSE ZORIENTATION - END AS 'Orientation', - CASE - ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION - WHEN 1 THEN - 'Horizontal (left)' - WHEN 3 THEN - 'Horizontal (right)' - WHEN 6 THEN - 'Vertical (up)' - WHEN 8 THEN - 'Vertical (down)' ELSE ZORIENTATION - END AS 'Org_Orientation', - ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME AS 'TimeZoneName', - ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET AS 'TimeZoneOffset', - ZADDITIONALASSETATTRIBUTES.ZINFERREDTIMEZONEOFFSET AS 'InferredTimeZoneOffset', - ZASSET.ZLOCATIONDATA AS 'FileLocationData', - CASE - ZASSET.ZLATITUDE - WHEN - 180.0 THEN - '' ELSE ZASSET.ZLATITUDE - END AS 'Latitude', - CASE - ZASSET.ZLONGITUDE - WHEN - 180.0 THEN - '' ELSE ZASSET.ZLONGITUDE - END AS 'Longitude', - CASE - ZADDITIONALASSETATTRIBUTES.ZSHIFTEDLOCATIONISVALID - WHEN 0 THEN - 'No' - WHEN 1 THEN - 'Yes' - END AS 'ShiftedLocationValid', - CASE - ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATAISVALID - WHEN 0 THEN - 'No_Check_SceneAnalysis' - WHEN 1 THEN - 'Yes_Check_SceneAnalysis' - END AS 'ReverseLocationDataIsValid', - ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA AS 'OrgFileReverseLocationData', - ZASSET.Zthumbnailindex AS 'ThumbnailIndex', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILWIDTH AS 'EmbeddedThumbnailWidth', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILHEIGHT AS 'EmbeddedThumbnailHeight', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILOFFSET AS 'EmbeddedThumbnailOffset', - ZADDITIONALASSETATTRIBUTES.ZEMBEDDEDTHUMBNAILLENGTH AS 'EmbeddedThumbnailLenght', - ZASSET.ZMOMENT AS 'MomentPK', - ZMOMENT.ZTITLE AS 'MomentTitle', - DateTime( ZMOMENT.ZSTARTDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentStartDate', - DateTime( ZMOMENT.Zrepresentativedate + 978307200, 'UNIXEPOCH' ) AS 'MomentRepresentativeDate', - DateTime( ZMOMENT.ZMODIFICATIONDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentModificationDate', - DateTime( ZMOMENT.ZENDDATE + 978307200, 'UNIXEPOCH' ) AS 'MomentEndDate', - CASE - ZMOMENT.ZTRASHEDSTATE - WHEN 1 THEN - 'In_Trash' - WHEN 0 THEN - 'Not_In_Trash' ELSE ZMOMENT.ZTRASHEDSTATE - END AS 'MomentTrashState', - CASE - ZMOMENT.Zapproximatelatitude - WHEN - 180.0 THEN - '' ELSE ZMOMENT.Zapproximatelatitude - END AS 'MomentApproxLatitude', - CASE - ZMOMENT.Zapproximatelongitude - WHEN - 180.0 THEN - '' ELSE ZMOMENT.Zapproximatelongitude - END AS 'MomentApproxLongitude', - ZASSET.ZUUID AS 'UUID', - ZASSET.ZMEDIAGROUPUUID AS 'MediaGroupUUID', - ZASSET.ZCLOUDASSETGUID AS 'CloudAssetGUID', - ZADDITIONALASSETATTRIBUTES.ZPUBLICGLOBALUUID AS 'PublicGlobalUUID', - ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT AS 'MasterFingerprint', - ZADDITIONALASSETATTRIBUTES.ZADJUSTEDFINGERPRINT AS 'AdjustedFingerprint' - FROM - ZASSET - LEFT JOIN ZMOMENT ON ZASSET.ZMOMENT = ZMOMENT.Z_PK - JOIN ZADDITIONALASSETATTRIBUTES ON ZASSET.ZADDITIONALATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK - LEFT JOIN ZDETECTEDFACE ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZDETECTEDFACE.ZASSET - LEFT JOIN ZPERSON ON ZPERSON.Z_PK = ZDETECTEDFACE.ZPERSON - LEFT JOIN Z_26ASSETS ON ZASSET.Z_PK = Z_26ASSETS.Z_3ASSETS - LEFT JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS - """) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - counter = 0 - if usageentries > 0: - for row in all_rows: - postal_address = '' - postal_address_subadminarea = '' - postal_address_sublocality = '' - - if row[61] is not None: - pathto = os.path.join(report_folder, 'ReverseLocationData' + str(counter) + '.bplist') - with open(pathto, 'ab') as wf: - wf.write(row[61]) - - with open(pathto, 'rb') as f: - try: - deserialized_plist = nd.deserialize_plist(f) - postal_address = deserialized_plist['postalAddress']['_formattedAddress'] - postal_address_subadminarea = deserialized_plist['postalAddress']['_subAdministrativeArea'] - postal_address_sublocality = deserialized_plist['postalAddress']['_subLocality'] - - except: - logfunc('Error reading exported bplist from Asset PK' + row[0]) - deserialized_plist = None - - data_list.append((row[0], row[0], postal_address, postal_address_subadminarea, - postal_address_sublocality, row[1], row[2], row[3], row[4], row[5], row[6], row[7], - row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], - row[17], row[18], row[19], row[20], row[21], row[22], row[23], row[24], row[25], - row[26], row[27], row[28], row[29], row[30], row[31], row[32], row[33], row[34], - row[35], row[36], row[37], row[38], row[39], row[40], row[41], row[42], row[43], - row[44], row[45], row[46], row[47], row[48], row[49], row[50], row[51], row[52], - row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60], row[61], - row[62], row[63], row[64], row[65], row[66], row[67], row[68], row[69], row[70], - row[71], row[72], row[73], row[74], row[75], row[76], row[77], row[78], row[79], - row[80], row[81])) - - counter += 1 - - description = '' - report = ArtifactHtmlReport('Photos.sqlite') - report.start_artifact_report(report_folder, 'Metadata', description) - report.add_script() - data_headers = ( - 'Timestamp', 'Date Created', 'Postal Address', 'Postal Subadmin Area', 'Postal Sublocality', - 'Asset ZPK', - 'Add Attributes Key', 'Detected Face Asset', 'Kind', 'EXIF Timestamp', 'Scene Analysis Timestamp', - 'Analysis State Modified Date', 'Add Date', 'Filename', 'Original Filename', 'Album Title', - 'Creator Bundle ID', 'Editor Bundle ID', 'Directory', 'Uniform ID', 'Saved Asset Type', - 'Face Detected in Photo', 'Display Name', 'Full Name', 'Face Count', 'Person', 'Contact Blob', - 'Person UUID', 'Detected Face Quality', 'Age Type Estimate', 'Gender', 'Glasses Type', - 'Facial Hair Type', - 'Baldness', 'Color Space', 'Duration', 'Video Duration', 'Complete', 'Visibility State', 'Favorite', - 'Hidden File?', 'Trash State', 'File Trash Date', 'View Count', 'Play Count', 'Share Count', - 'Last Shared Date', 'File Modification Date', 'Has Adjustments?', 'Adjustment Timestamp', - 'Original File Size', 'File Height', 'Org File Height', 'File Width', 'Org File Width', 'Orientation', - 'Org Orientation', 'Timezone Name', 'Timezone Offset', 'Infered Timezone Offset', 'File Location Data', - 'Latitude', 'Longitude', 'Shifted Location Valid', 'Reverse Location Data is Valid', - 'Org File Reverse Location Data', 'Thumbnail Index', 'Embedded Thumbnail Width', - 'Embedded Thumbnail Height', 'Embedded Thumbnail Offset', 'Embedded Thumbnail Lenght', 'Moment PK', - 'Moment Title', 'Moment Start Date', 'Moment Representative Date', 'Moment Modification Date', - 'Moment End Date', 'Moment Trash State', 'Moment Approx Latitude', 'Moment Approx Longitude', 'UUID', - 'Media Group UUID', 'Cloud Assest GUID', 'Public Global UUID', 'Master Fingetprint', - 'Adjusted Fingerprint') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Photos-sqlite Metadata' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Photos-sqlite Metadata' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Photos-sqlite Metadata' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - else: - logfunc('No data available for Photos.sqlite metadata') - - db.close() - return diff --git a/scripts/artifacts/protonMail.py b/scripts/artifacts/protonMail.py deleted file mode 100644 index 6c7c35da..00000000 --- a/scripts/artifacts/protonMail.py +++ /dev/null @@ -1,256 +0,0 @@ -import os -import plistlib -import pgpy -import html -import json -import ccl_bplist -import sqlite3 -import hashlib -import random -import magic -from base64 import b64encode, b64decode -from datetime import datetime -from io import BytesIO -from Crypto.Cipher import AES -from pathlib import Path -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly, media_to_html - -def get_protonMail(files_found, report_folder, seeker): - data_list = [] - - p = Path(__file__).parents[1] - - my_path = Path(p).joinpath('keychain') - - #platform = is_platform_windows() - #if platform: - # my_path = my_path.replace('/', '\\') - - if len(os.listdir(my_path)) == 1: - logfunc("No keychain provided") - return - - else: - file = os.listdir(my_path) - for x in file: - if x.endswith('plist'): - keychain_plist_path = Path(my_path).joinpath(x) - - for file_found in files_found: - if 'group.ch.protonmail.protonmail.plist' in file_found: - plist_name = file_found - if file_found.endswith('ProtonMail.sqlite'): - db_name = file_found - - with open(keychain_plist_path,'rb') as f : - plist = plistlib.load(f) - - keychainVal={} - if type(plist) == list: - for dd in plist: - if type(dd) == dict: - if 'svce' in dd: - if 'protonmail' in str(dd['svce']) : - #print(dd) - keychainVal[dd['acct']]=dd['v_Data'] - else: - for d in plist: - for dd in plist[d]: - if type(dd) == dict: - if 'svce' in dd: - if 'protonmail' in str(dd['svce']): - #print(dd) - keychainVal[dd['acct']]=dd['v_Data'] - - mainKey = keychainVal[b'NoneProtection'] - IVsize = 16 - - def decryptWithMainKey(encrypted): - iv = encrypted[:IVsize] - cipher = AES.new(mainKey, AES.MODE_CTR, initial_value=iv, nonce=b'') - return cipher.decrypt(encrypted[IVsize:]) - - with open(plist_name,'rb') as p : - prefplist = plistlib.load(p) - - - enc_val = prefplist.get('authKeychainStoreKeyProtectedWithMainKey', 'empty') - if enc_val != 'empty': - pass - elif keychainVal[b'authKeychainStoreKeyProtectedWithMainKey']: - enc_val = keychainVal[b'authKeychainStoreKeyProtectedWithMainKey'] - else: - logfunc('Decryption key not found in the keychain or the application plist.') - return - - dec_val = decryptWithMainKey(enc_val) - - keychainStorePlist1 = ccl_bplist.load(BytesIO(dec_val)) - keychainStorePlist = ccl_bplist.load(BytesIO(keychainStorePlist1[0])) - keychainStore = ccl_bplist.deserialise_NsKeyedArchiver(keychainStorePlist, parse_whole_structure=True) - privateKeyCoderKey = keychainStore['root']['NS.objects'][0]['privateKeyCoderKey'] - - key, _ = pgpy.PGPKey.from_blob(privateKeyCoderKey) - pwdKey = keychainStore['root']['NS.objects'][0]['AuthCredential.Password'] - - def decrypt_message(encm): - if('-----BEGIN PGP MESSAGE-----') in encm: - with key.unlock(pwdKey): - assert key.is_unlocked - message_from_blob = pgpy.PGPMessage.from_blob(encm) - decm = key.decrypt(message_from_blob).message - #print(decm) - return html.unescape(decm.encode('cp1252', errors='ignore').decode('utf8', errors='ignore')) - else: - return encm - - def decrypt_attachment(proton_path, out_path, key, pwdKey, keyPacket, encfilename, decfilename): - att = None - for r, _, f in os.walk(proton_path): - for file in f: - if encfilename in file: - att=os.path.join(r,file) - break - if att: - with key.unlock(pwdKey): - assert key.is_unlocked - with open(att, 'rb') as attfh: - buf = b64decode(keyPacket) - buf += attfh.read() - att_from_blob = pgpy.PGPMessage.from_blob(buf) - decatt = key.decrypt(att_from_blob).message - itemnum = str(random.random()) - with open(os.path.join(out_path,itemnum+decfilename),'wb') as outatt: - outatt.write(decatt) - return os.path.join(out_path,itemnum+decfilename) - - return None - - db = open_sqlite_db_readonly(db_name) - cursor = db.cursor() - cursor.execute('''SELECT - ZMESSAGE.ZTIME, - ZMESSAGE.ZBODY, - ZMESSAGE.ZMIMETYPE, - ZMESSAGE.ZTOLIST, - ZMESSAGE.ZREPLYTOS, - ZMESSAGE.ZSENDER, - ZMESSAGE.ZTITLE, - ZMESSAGE.ZISENCRYPTED, - ZMESSAGE.ZNUMATTACHMENTS, - ZATTACHMENT.ZFILESIZE, - ZATTACHMENT.ZFILENAME, - ZATTACHMENT.ZMIMETYPE, - ZATTACHMENT.ZHEADERINFO, - ZATTACHMENT.ZLOCALURL, - ZATTACHMENT.ZKEYPACKET - FROM ZMESSAGE - LEFT JOIN ZATTACHMENT ON ZMESSAGE.Z_PK = ZATTACHMENT.ZMESSAGE - ''') - - all_rows = cursor.fetchall() - data_list = [] - if len(all_rows) > 0: - for row in all_rows: - aggregatorto = '' - aggregatorfor = '' - - time = row[0] - decryptedtime = datetime.fromtimestamp(time+978307200) - - decryptedbody = decrypt_message(row[1]) - - mime = row[2] - - to = json.loads(plistlib.loads(decryptWithMainKey(row[3]))[0]) - for r in to: - address = r['Address'] - name = r['Name'] - aggregatorto = f"{address} {name}" - - try: - replyto = json.loads(plistlib.loads(decryptWithMainKey(row[4]))[0]) - for r in replyto: - address = r['Address'] - name = r['Name'] - aggregatorfor = f"{address} {name}" - except: - aggregatorfor = '' - - try: - sender = json.loads(plistlib.loads(decryptWithMainKey(row[5]))[0]) - name = sender['Name'] - address = sender['Address'] - sender_info = f'{address} {name}' - except: - sender_info = '' - - title = plistlib.loads(decryptWithMainKey(row[6]))[0] - - isencrypted = row[7] - - ZNUMATTACHMENTS = row[8] - - ZFILESIZE = row[9] - - try: - ZFILENAME = plistlib.loads(decryptWithMainKey(row[10]))[0] - except: - ZFILENAME = "" - - try: - AMIMETYPE = plistlib.loads(decryptWithMainKey(row[11]))[0] - except: - AMIMETYPE = "" - - if row[12]: - zheaderinfo = decryptWithMainKey(row[12]) - - attpath = '' - if row[13]: - encfilename = plistlib.loads(row[13])['$objects'][2].split('/')[-1] - guidi = plistlib.loads(row[13])['$objects'][2].split('/')[-4] - out_path = report_folder - - for match in files_found: - if f'/Data/Application/{guidi}/tmp/attachments' in match: - proton_path = match.split('/attachments')[0] - break - elif f'\\Data\\Application\\{guidi}\\tmp\\attachments' in match: - proton_path = match.split('\\attachments')[0] - - attpath = decrypt_attachment(proton_path, out_path, key, pwdKey, row[14], encfilename, ZFILENAME) - - mimetype = magic.from_file(attpath, mime = True) - - if 'video' in mimetype: - attpath = f'' - elif 'image' in mimetype: - attpath = f'' - else: - attpath = f' Link to {mimetype} ' - - data_list.append((decryptedtime, sender_info, aggregatorto, aggregatorfor, title, decryptedbody, mime, isencrypted, ZFILESIZE, attpath, ZFILENAME, AMIMETYPE)) - - encfilename = '' - - if len(data_list) > 0: - report = ArtifactHtmlReport('Proton Mail - Decrypted Emails') - report.start_artifact_report(report_folder, 'Proton Mail - Decrypted Emails') - report.add_script() - data_headers = ('Timestamp', 'Sender', 'To', 'Reply To', 'Title', 'Body', 'Mime', 'Is encrypted?', 'File Size','Attachment','Decrypted Attachment Filename', 'Type') - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Sender', 'To', 'Reply To', 'Body', 'File Name', 'Type','Attachment']) - report.end_artifact_report() - - tsvname = 'Proton Mail - Decrypted Emails' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Proton Mail - Decrypted Emails' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Proton Mail - Decrypted Emails') - - - \ No newline at end of file diff --git a/scripts/artifacts/queryPredictions.py b/scripts/artifacts/queryPredictions.py deleted file mode 100644 index 3b1a24d8..00000000 --- a/scripts/artifacts/queryPredictions.py +++ /dev/null @@ -1,48 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def get_queryPredictions(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - datetime(creationTimestamp, "UNIXEPOCH") as START, - content, - isSent, - conversationId, - id, - uuid - from messages - ''') - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - data_list.append((row[0],row[1],row[2],row[3],row[4],row[5])) - - report = ArtifactHtmlReport('Query Predictions') - report.start_artifact_report(report_folder, 'Query Predictions') - report.add_script() - data_headers = ('Timestamp','Content','Is Sent?','Conversation ID','ID','UUID') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Query Predictions' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Query Predictions' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data available in table') - - db.close() - return \ No newline at end of file diff --git a/scripts/artifacts/quickLook.py b/scripts/artifacts/quickLook.py deleted file mode 100644 index 8c13fa45..00000000 --- a/scripts/artifacts/quickLook.py +++ /dev/null @@ -1,52 +0,0 @@ -import glob -import os -import pathlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, kmlgen, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_quickLook(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('cloudthumbnails.db'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - datetime("last_hit_date", 'unixepoch') as lasthitdate, - last_seen_path, - size - from thumbnails - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2])) - - description = 'Listing of iCloud files accessed by the Quick Look function.' - report = ArtifactHtmlReport('iCloud Quick Look') - report.start_artifact_report(report_folder, 'iCloud Quick Look', description) - report.add_script() - data_headers = ('Last Hit Date','Last Seen Path','Size') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'iCloud Quick Look' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'iCloud Quick Look' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No iCloud Quick Look DB data available') - - db.close() - return diff --git a/scripts/artifacts/recentApphistory.py b/scripts/artifacts/recentApphistory.py deleted file mode 100644 index bac860af..00000000 --- a/scripts/artifacts/recentApphistory.py +++ /dev/null @@ -1,40 +0,0 @@ -import biplist -import datetime - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - - -def get_recentApphistory(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - with open(file_found, 'rb') as f: - plist = biplist.readPlist(f) - RecentAppHistory = plist.get('CARRecentAppHistory') - - if RecentAppHistory is not None: - if len(RecentAppHistory) > 0: - for bundleid, timestamp in RecentAppHistory.items(): - timestamp = (datetime.datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S')) - data_list.append((timestamp, bundleid)) - - if len(data_list) > 0: - description = 'CarPlay recent app history.' - report = ArtifactHtmlReport('CarPlay Recent App History') - report.start_artifact_report(report_folder, 'CarPlay Recent App History', description) - report.add_script() - data_headers = ('Timestamp','Bundle ID') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'CarPlay Recent App History' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'CarPlay Recent App History' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No data on CarPlay Recent App History') - - \ No newline at end of file diff --git a/scripts/artifacts/reminders.py b/scripts/artifacts/reminders.py deleted file mode 100644 index bc53ef1e..00000000 --- a/scripts/artifacts/reminders.py +++ /dev/null @@ -1,51 +0,0 @@ -from os.path import dirname - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_reminders(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - DATETIME(ZCREATIONDATE+978307200,'UNIXEPOCH'), - DATETIME(ZLASTMODIFIEDDATE+978307200,'UNIXEPOCH'), - ZNOTES, - ZTITLE1 - FROM ZREMCDOBJECT - WHERE ZTITLE1 <> '' - ''') - - all_rows = cursor.fetchall() - sqlite_file = file_found - - if len(all_rows) > 0: - location_file_found = sqlite_file.split('Stores/', 1)[1] - for row in all_rows: - data_list.append((row[0], row[3], row[2], row[1], location_file_found)) - - dir_file_found = dirname(sqlite_file).split('Stores', 1)[0] + 'Stores' - - report = ArtifactHtmlReport('Reminders') - report.start_artifact_report(report_folder, 'Reminders') - report.add_script() - data_headers = ('Creation Date', 'Title', 'Note to Reminder', 'Last Modified', 'File Location') - report.write_artifact_data_table(data_headers, data_list, dir_file_found) - report.end_artifact_report() - - tsvname = 'Reminders' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Reminders' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Reminders available') - - db.close() - return diff --git a/scripts/artifacts/restoreLog.py b/scripts/artifacts/restoreLog.py deleted file mode 100644 index e7eca0ed..00000000 --- a/scripts/artifacts/restoreLog.py +++ /dev/null @@ -1,206 +0,0 @@ -import datetime -import os - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows - -def get_restoreLog(files_found, report_folder, seeker): - - data_list = [] - pattern = 'data = ' - pattern1 = '\"originalOSVersion\":\"' - pattern2 = '\"currentOSVersion\":\"' - pattern3 = '\"deviceModel\":\"' - pattern4 = '\"eventTime\":\"' - pattern5 = '\"batteryIsCharging\":' - pattern6 = '\"deviceClass\":\"' - pattern7 = '\"event\":\"' - og_version_num = '' - cur_version_num = '' - originalOSBuild = '' - currentOSBuild = '' - - OS_dict = { - "15A372":"11.0", - "15A402":"11.0.1", - "15A403":"11.0.1", - "15A8391":"11.0.1", - "15A421":"11.0.2", - "15A432":"11.0.3", - "15B93":"11.1", - "15B101":"11.1", - "15B150":"11.1.1", - "15B202":"11.1.2", - "15C114":"11.2", - "15C153":"11.2.1", - "15C202":"11.2.2", - "15D60":"11.2.5", - "15D100":"11.2.6", - "15E216":"11.3", - "15E218":"11.3", - "15E302":"11.3.1", - "15F79":"11.4", - "15G77":"11.4.1", - "16A366":"12.0", - "16A404":"12.0.1", - "16A405":"12.0.1", - "16B92":"12.1", - "16B93":"12.1", - "16B94":"12.1", - "16C50":"12.1.1", - "16C104":"12.1.2", - "16D39":"12.1.3", - "16D40":"12.1.3", - "16D57":"12.1.4", - "16E227":"12.2", - "16F156":"12.3", - "16F203":"12.3.1", - "16F8202":"12.3.1", - "16F250":"12.3.2", - "16G77":"12.4", - "16G102":"12.4.1", - "16G114":"12.4.2", - "16G130":"12.4.3", - "16G140":"12.4.4", - "16G161":"12.4.5", - "16G183":"12.4.6", - "16G192":"12.4.7", - "16G201":"12.4.8", - "16H5":"12.4.9", - "16H20":"12.5", - "16H22":"12.5.1", - "16H30":"12.5.2", - "16H41":"12.5.3", - "16H50":"12.5.4", - "16H62":"12.5.5", - "17A577":"13.0", - "17A844":"13.1", - "17A854":"13.1.1", - "17A860":"13.1.2", - "17A861":"13.1.2", - "17A878":"13.1.3", - "17B84":"13.2", - "17B90":"13.2.1", - "17B102":"13.2.2", - "17B111":"13.2.3", - "17C54":"13.3", - "17D50":"13.3.1", - "17E255":"13.4", - "17E8255":"13.4", - "17E262":"13.4.1", - "17E8258":"13.4.1", - "17F75":"13.5", - "17F80":"13.5.1", - "17G68":"13.6", - "17G80":"13.6.1", - "17H35":"13.7", - "18A373":"14.0", - "18A393":"14.0.1", - "18A8395":"14.1", - "18B92":"14.2", - "18B111":"14.2", - "18B121":"14.2.1", - "18C66":"14.3", - "18D52":"14.4", - "18D61":"14.4.1", - "18D70":"14.4.2", - "18E199":"14.5", - "18E212":"14.5.1", - "18F72":"14.6", - "18G69":"14.7", - "18G82":"14.7.1", - "18H17":"14.8", - "18H107":"14.8.1", - "19A346":"15.0", - "19A348":"15.0.1", - "19A404":"15.0.2", - "19B74":"15.1", - "19B81":"15.1.1", - "19C56":"15.2", - "19C57":"15.2", - "19C63":"15.2.1", - "19D50":"15.3", - "19D52":"15.3.1", - "19E241":"15.4", - } - - for file_found in files_found: - file_found = str(file_found) - - with open(file_found, "r", encoding="utf-8") as f: - data = f.readlines() - for line in data: - if pattern in line: - - if pattern1 in line: - - if pattern1 in line: - splitline1 = line.partition(pattern1)[2] - originalOSBuild = splitline1[:splitline1.find("\"")] - - for key, value in OS_dict.items(): - if originalOSBuild == key: - og_version_num = value - break - else: og_version_num = "Unknown" - else: pass - - if pattern2 in line: - splitline2 = line.partition(pattern2)[2] - currentOSBuild = splitline2[:splitline2.find("\"")] - - for key, value in OS_dict.items(): - if currentOSBuild == key: - cur_version_num = value - break - else: cur_version_num = "Unknown" - - if pattern3 in line: - splitline3 = line.partition(pattern3)[2] - deviceModel = splitline3[:splitline3.find("\"")] - else: pass - - if pattern4 in line: - splitline4 = line.partition(pattern4)[2] - eventTime = splitline4[:splitline4.find("\"")] - timestamp_formatted = datetime.datetime.fromtimestamp(int(eventTime)/1000).strftime('%Y-%m-%d %H:%M:%S') - else: pass - - if pattern5 in line: - splitline5 = line.partition(pattern5)[2] - batteryIsCharging = splitline5[:splitline5.find(",")] - else: pass - - if pattern6 in line: - splitline6 = line.partition(pattern6)[2] - deviceClass = splitline6[:splitline6.find("\"")] - else: pass - - if pattern7 in line: - splitline7 = line.partition(pattern7)[2] - event = splitline7[:splitline7.find("\"")] - else: pass - - data_list.append((timestamp_formatted,originalOSBuild,og_version_num,currentOSBuild,cur_version_num,event,deviceClass,deviceModel,batteryIsCharging)) - - else: pass - - - num_entries = len(data_list) - if num_entries > 0: - report = ArtifactHtmlReport('Mobile Software Update - Restore Log') - report.start_artifact_report(report_folder, 'Mobile Software Update - Restore Log') - report.add_script() - data_headers = ('Timestamp','Original OS Build','Original OS Version','Current OS Build','Current OS Version','Event','Device','Model','Battery Is Charging') - - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Mobile Software Update - Restore Log' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Mobile Software Update - Restore Log' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Mobile Software Update - Restore Log data available') \ No newline at end of file diff --git a/scripts/artifacts/routineD.py b/scripts/artifacts/routineD.py new file mode 100644 index 00000000..643d30d5 --- /dev/null +++ b/scripts/artifacts/routineD.py @@ -0,0 +1,125 @@ +import glob +import os +import pathlib +import sqlite3 + +from scripts.artifact_report import ArtifactHtmlReport +from scripts.ilapfuncs import logfunc, tsv, kmlgen, timeline, is_platform_windows, open_sqlite_db_readonly + + +def get_routineD(files_found, report_folder, seeker): + for file_found in files_found: + file_found = str(file_found) + + if file_found.endswith('Cache.sqlite'): + + db = open_sqlite_db_readonly(file_found) + cursor = db.cursor() + cursor.execute(''' + SELECT + DATETIME(ztimestamp+978307200,'UNIXEPOCH'), + zlatitude, zlongitude, zhorizontalaccuracy + FROM zrtcllocationmo + ORDER BY ztimestamp ASC + ''') + + all_rows = cursor.fetchall() + usageentries = len(all_rows) + data_list = [] + if usageentries > 0: + for row in all_rows: + data_list.append((row[0], row[1], row[2], row[3],)) + + description = '' + report = ArtifactHtmlReport('RoutineD - Cache.sqlite Geolocation') + report.start_artifact_report(report_folder, 'RoutineD - Cache.sqlite Geolocation', description) + report.add_script() + data_headers = ('Timestamp','Latitude','Longitude','Horizontal Accuracy') + report.write_artifact_data_table(data_headers, data_list, file_found) + report.end_artifact_report() + + tsvname = 'RoutineD - Cache.sqlite Geolocation' + tsv(report_folder, data_headers, data_list, tsvname) + + tlactivity = 'RoutineD - Cache.sqlite Geolocation' + timeline(report_folder, tlactivity, data_list, data_headers) + + kmlactivity = 'RoutineD - Cache.sqlite Geolocation' + kmlgen(report_folder, kmlactivity, data_list, data_headers) + else: + logfunc('No RoutineD - Cache.sqlite Geolocation data available') + + if file_found.endswith('Local.sqlite'): + + db = open_sqlite_db_readonly(file_found) + cursor = db.cursor() + cursor.execute(''' + SELECT DATETIME(ztimestamp+978307200,'UNIXEPOCH'), + zlatitude, zlongitude, zhorizontalaccuracy + FROM zrtcllocationmo + ORDER BY ztimestamp ASC + ''') + + all_rows = cursor.fetchall() + usageentries = len(all_rows) + data_list = [] + if usageentries > 0: + for row in all_rows: + data_list.append((row[0], row[1], row[2], row[3],)) + + description = '' + report = ArtifactHtmlReport('RoutineD - Local.sqlite Geolocation') + report.start_artifact_report(report_folder, 'RoutineD - Local.sqlite Geolocation', description) + report.add_script() + data_headers = ('Timestamp','Latitude','Longitude','Horizontal Accuracy') + report.write_artifact_data_table(data_headers, data_list, file_found) + report.end_artifact_report() + + tsvname = 'RoutineD - Local.sqlite Geolocation' + tsv(report_folder, data_headers, data_list, tsvname) + + tlactivity = 'RoutineD - Local.sqlite Geolocation' + timeline(report_folder, tlactivity, data_list, data_headers) + + kmlactivity = 'RoutineD - Local.sqlite Geolocation' + kmlgen(report_folder, kmlactivity, data_list, data_headers) + else: + logfunc('No RoutineD - Local.sqlite Geolocation data available') + + + if file_found.endswith('Cloud.sqlite'): + + db = open_sqlite_db_readonly(file_found) + cursor = db.cursor() + cursor.execute(''' + SELECT DATETIME(ztimestamp+978307200,'UNIXEPOCH'), + zlatitude, zlongitude, zhorizontalaccuracy + FROM zrtcllocationmo + ORDER BY ztimestamp ASC + ''') + + all_rows = cursor.fetchall() + usageentries = len(all_rows) + data_list = [] + if usageentries > 0: + for row in all_rows: + data_list.append((row[0], row[1], row[2], row[3],)) + + description = '' + report = ArtifactHtmlReport('RoutineD - Cloud.sqlite Geolocation') + report.start_artifact_report(report_folder, 'RoutineD - Cloud.sqlite Geolocation', description) + report.add_script() + data_headers = ('Timestamp','Latitude','Longitude','Horizontal Accuracy') + report.write_artifact_data_table(data_headers, data_list, file_found) + report.end_artifact_report() + + tsvname = 'RoutineD - Cloud.sqlite Geolocation' + tsv(report_folder, data_headers, data_list, tsvname) + + tlactivity = 'RoutineD - Cloud.sqlite Geolocation' + timeline(report_folder, tlactivity, data_list, data_headers) + + kmlactivity = 'RoutineD - Cloud.sqlite Geolocation' + kmlgen(report_folder, kmlactivity, data_list, data_headers) + else: + logfunc('No RoutineD - Cloud.sqlite Geolocation data available') \ No newline at end of file diff --git a/scripts/artifacts/safariBookmarks.py b/scripts/artifacts/safariBookmarks.py deleted file mode 100644 index 0c9c0313..00000000 --- a/scripts/artifacts/safariBookmarks.py +++ /dev/null @@ -1,49 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import json - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_safariBookmarks(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - SELECT - title, - url, - hidden - FROM - bookmarks - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2])) - - description = '' - report = ArtifactHtmlReport('Safari Browser Bookmarks') - report.start_artifact_report(report_folder, 'Bookmarks', description) - report.add_script() - data_headers = ('Title','URL','Hidden') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Safari Browser Bookmarks' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('No data available in table') - - db.close() - return - \ No newline at end of file diff --git a/scripts/artifacts/safariFavicons.py b/scripts/artifacts/safariFavicons.py deleted file mode 100644 index 26fc35bd..00000000 --- a/scripts/artifacts/safariFavicons.py +++ /dev/null @@ -1,60 +0,0 @@ -import sqlite3 -import os -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_safariFavicons(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('Favicons.db'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - Select - datetime('2001-01-01', "timestamp" || ' seconds') as icon_timestamp, - page_url.url, - icon_info.url, - icon_info.width, - icon_info.height, - icon_info.has_generated_representations - FROM icon_info - LEFT JOIN page_url - on icon_info.uuid = page_url.uuid - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5])) - - description = 'Safari Favicons' - report = ArtifactHtmlReport('Favicons') - report.start_artifact_report(report_folder, 'Favicons', description) - report.add_script() - data_headers = ('Timestamp', 'Page URL', 'Icon URL', 'Width', 'Height', 'Generated Representations?' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Safari Favicons' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Safari Favicons' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Safari Favicons data available') - - db.close() - - - \ No newline at end of file diff --git a/scripts/artifacts/safariRecentWebSearches.py b/scripts/artifacts/safariRecentWebSearches.py deleted file mode 100644 index baa041f8..00000000 --- a/scripts/artifacts/safariRecentWebSearches.py +++ /dev/null @@ -1,38 +0,0 @@ -import biplist -import plistlib -import sys - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline - -def get_safariRecentWebSearches(files_found, report_folder, seeker): - data_list = [] - for file_found in files_found: - file_found = str(file_found) - with open(file_found, "rb") as fp: - try: - if sys.version_info >= (3, 9): - plist = plistlib.load(fp) - else: - plist = biplist.readPlist(fp) - searches = plist.get('RecentWebSearches', []) - for search in searches: - term = search.get('SearchString', '') - date = search.get('Date', '') - data_list.append((date, term)) - except (biplist.InvalidPlistException, plistlib.InvalidFileException) as ex: - logfunc(f'Failed to read plist {file_found} ' + str(ex)) - - if data_list: - report = ArtifactHtmlReport('Safari Recent WebSearches') - report.start_artifact_report(report_folder, 'Recent WebSearches') - report.add_script() - data_headers = ('Date','Search Term') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Recent WebSearches' - tsv(report_folder, data_headers, data_list, tsvname) - timeline(report_folder, tsvname, data_list, data_headers) - else: - logfunc('No data for recent web searches') \ No newline at end of file diff --git a/scripts/artifacts/safariTabs.py b/scripts/artifacts/safariTabs.py deleted file mode 100644 index ac2c68d7..00000000 --- a/scripts/artifacts/safariTabs.py +++ /dev/null @@ -1,55 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import json - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_safariTabs(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - select - datetime(last_viewed_time+978307200,'unixepoch'), - title, - url, - user_visible_url, - opened_from_link, - private_browsing - from - tabs - """) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5])) - - description = '' - report = ArtifactHtmlReport('Safari Browser Tabs') - report.start_artifact_report(report_folder, 'Tabs', description) - report.add_script() - data_headers = ('Last Viewed Time','Title','URL','User Visible URL','Opened from Link', 'Private Browsing') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Safari Browser Tabs' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Safari Browser Tabs' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No data available in table') - - db.close() - return - \ No newline at end of file diff --git a/scripts/artifacts/safariWebsearch.py b/scripts/artifacts/safariWebsearch.py deleted file mode 100644 index 846a755c..00000000 --- a/scripts/artifacts/safariWebsearch.py +++ /dev/null @@ -1,65 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import json - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_safariWebsearch(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(""" - select - datetime(history_visits.visit_time+978307200,'unixepoch') , - history_items.url, - history_items.visit_count, - history_visits.title, - case history_visits.origin - when 1 then "icloud synced" - when 0 then "visited local device" - else history_visits.origin - end "icloud sync", - history_visits.load_successful, - history_visits.id, - history_visits.redirect_source, - history_visits.redirect_destination - from history_items, history_visits - where history_items.id = history_visits.history_item - and history_items.url like '%search?q=%' - """ - ) - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - search = row[1].split('search?q=')[1].split('&')[0] - search = search.replace('+', ' ') - data_list.append((row[0], search, row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8])) - - description = '' - report = ArtifactHtmlReport('Safari Browser') - report.start_artifact_report(report_folder, 'Search Terms', description) - report.add_script() - data_headers = ('Visit Time','Search Term','URL','Visit Count','Title','iCloud Sync','Load Successful','Visit ID','Redirect Source','Redirect Destination' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Safari Web Search' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Safari Web Search' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No data available in table') - - db.close() - return - \ No newline at end of file diff --git a/scripts/artifacts/script.txt b/scripts/artifacts/script.txt deleted file mode 100644 index 7abe62b6..00000000 --- a/scripts/artifacts/script.txt +++ /dev/null @@ -1,46 +0,0 @@ - - diff --git a/scripts/artifacts/slack.py b/scripts/artifacts/slack.py deleted file mode 100644 index 4b4182d6..00000000 --- a/scripts/artifacts/slack.py +++ /dev/null @@ -1,339 +0,0 @@ -from os.path import dirname, join -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_slack(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('main_db'): - break - - deprecated = 0 - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") - all_rows = cursor.fetchall() - usageentries = len(all_rows) - - for row in all_rows: - if 'ZSLKDEPRECATEDMESSAGE' in row[0]: - deprecated = 1 - - if deprecated == 1: - squery = (''' - select distinct - datetime(ZSLKDEPRECATEDMESSAGE.ZTIMESTAMP, 'unixepoch') as MessageTimeStamp, - ZSLKDEPRECATEDMESSAGE.ZUSERID as MessageGeneratedFrom, - ZSLKDEPRECATEDCOREDATAUSER.ZREALNAME as MessageGeneratedFromName, - ZSLKDEPRECATEDBASECHANNEL.ZNAME as MessageSentToChannelName, - ZSLKDEPRECATEDMESSAGE.ZTEXT, - json_extract(ZFILEIDS, '$[0]') as HasSharedFile, - ZSLKDEPRECATEDMESSAGE.ZCHANNELID, - ZSLKDEPRECATEDBASECHANNEL.ZTSID, - ZSLKDEPRECATEDBASECHANNEL.ZTSID1, - ZSLKDEPRECATEDCOREDATAUSER.ZTSID - from ZSLKDEPRECATEDMESSAGE, ZSLKDEPRECATEDBASECHANNEL,ZSLKDEPRECATEDCOREDATAUSER - where ZSLKDEPRECATEDCOREDATAUSER.ZTSID = ZSLKDEPRECATEDMESSAGE.ZUSERID and - (ZSLKDEPRECATEDBASECHANNEL.ZTSID = ZSLKDEPRECATEDMESSAGE.ZCHANNELID or ZSLKDEPRECATEDBASECHANNEL.ZTSID1 = ZSLKDEPRECATEDMESSAGE.ZCHANNELID) - order by ZSLKDEPRECATEDMESSAGE.ZTIMESTAMP - ''') - else: - squery = (''' - select distinct - datetime(ZSLKMESSAGE.ZTIMESTAMP, 'unixepoch') as MessageTimeStamp, - ZSLKMESSAGE.ZUSERID as MessageGeneratedFrom, - ZSLKCOREDATAUSER.ZREALNAME as MessageGeneratedFromName, - ZSLKBASECHANNEL.ZNAME as MessageSentToChannelName, - ZSLKMESSAGE.ZTEXT, - json_extract(ZFILEIDS, '$[0]') as HasSharedFile, - ZSLKMESSAGE.ZCHANNELID, - ZSLKBASECHANNEL.ZTSID, - ZSLKBASECHANNEL.ZTSID1, - ZSLKCOREDATAUSER.ZTSID - from ZSLKMESSAGE, ZSLKBASECHANNEL,ZSLKCOREDATAUSER - where ZSLKCOREDATAUSER.ZTSID = ZSLKMESSAGE.ZUSERID and - (ZSLKBASECHANNEL.ZTSID = ZSLKMESSAGE.ZCHANNELID or ZSLKBASECHANNEL.ZTSID1 = ZSLKMESSAGE.ZCHANNELID) - order by ZSLKMESSAGE.ZTIMESTAMP - ''') - - cursor.execute(squery) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9] )) - - description = 'Slack Messages' - report = ArtifactHtmlReport('Slack Messages') - report.start_artifact_report(report_folder, 'Slack Messages', description) - report.add_script() - data_headers = ('Timestamp', 'From', 'From Name', 'Channel Name', 'Message', 'Shared File', 'Channel ID','Channel SID', 'Channel SID1','User SID' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Slack Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Slack Messages' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Slack Messages data available') - - if deprecated == 1: - squery = (''' - select - ZSLKDEPRECATEDCOREDATAUSER.ZADMIN, - ZSLKDEPRECATEDCOREDATAUSER.ZOWNER, - ZSLKDEPRECATEDCOREDATAUSER.ZREALNAME, - ZSLKDEPRECATEDCOREDATAUSER.ZFIRSTNAME, - ZSLKDEPRECATEDCOREDATAUSER.ZLASTNAME, - ZSLKDEPRECATEDCOREDATAUSER.ZDISPLAYNAME, - ZSLKDEPRECATEDCOREDATAUSER.ZNAME, - ZSLKDEPRECATEDCOREDATAUSER.ZPHONE, - ZSLKDEPRECATEDCOREDATAUSER.ZTIMEZONE, - ZSLKDEPRECATEDCOREDATAUSER.ZTIMEZONEOFFSET, - ZSLKDEPRECATEDCOREDATAUSER.ZTIMEZONETITLE, - ZSLKDEPRECATEDCOREDATAUSER.ZTITLE, - ZSLKDEPRECATEDCOREDATAUSER.ZTSID, - ZSLKDEPRECATEDCOREDATAUSER.ZTEAMID - from ZSLKDEPRECATEDCOREDATAUSER - ''') - else: - squery = (''' - select - ZSLKCOREDATAUSER.ZADMIN, - ZSLKCOREDATAUSER.ZOWNER, - ZSLKCOREDATAUSER.ZREALNAME, - ZSLKCOREDATAUSER.ZFIRSTNAME, - ZSLKCOREDATAUSER.ZLASTNAME, - ZSLKCOREDATAUSER.ZDISPLAYNAME, - ZSLKCOREDATAUSER.ZNAME, - ZSLKCOREDATAUSER.ZPHONE, - ZSLKCOREDATAUSER.ZTIMEZONE, - ZSLKCOREDATAUSER.ZTIMEZONEOFFSET, - ZSLKCOREDATAUSER.ZTIMEZONETITLE, - ZSLKCOREDATAUSER.ZTITLE, - ZSLKCOREDATAUSER.ZTSID, - ZSLKCOREDATAUSER.ZTEAMID - from ZSLKCOREDATAUSER - ''') - - cursor.execute(squery) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13] )) - - description = 'Slack User Data' - report = ArtifactHtmlReport('Slack User Data') - report.start_artifact_report(report_folder, 'Slack User Data', description) - report.add_script() - data_headers = ('Admin', 'Owner', 'Real Name', 'First Name', 'Last Name', 'Display Name', 'Name','Phone', 'Timezone','Timezone Offset', 'Timezone Title', 'Title', 'SID', 'Team ID' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Slack User Data' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('No Slack User data available') - - if deprecated == 1: - squery = (''' - select distinct - datetime(ZSLKDEPRECATEDMESSAGE.ZTIMESTAMP, 'unixepoch') as MessageTimeStamp, - ZSLKDEPRECATEDMESSAGE.ZUSERID as MessageGeneratedFrom, - ZSLKDEPRECATEDCOREDATAUSER.ZREALNAME as MessageGeneratedFromName, - ZSLKDEPRECATEDBASECHANNEL.ZNAME as MessageSentToChannelName, - ZSLKDEPRECATEDMESSAGE.ZTEXT, - json_extract(ZFILEIDS, '$[0]') as HasSharedFile, - ZSLKDEPRECATEDFILE.ZMODESTRING, - ZSLKDEPRECATEDFILE.ZTITLE, - ZSLKDEPRECATEDFILE.ZTYPESTRING, - datetime(ZSLKDEPRECATEDFILE.ZTIMESTAMPNUMBER, 'unixepoch') as FileTimeStamp, - ZSLKDEPRECATEDFILE.ZPREVIEW, - ZSLKDEPRECATEDFILE.ZSIZE, - ZSLKDEPRECATEDFILE.ZPRIVATEDOWNLOADURL, - ZSLKDEPRECATEDFILE.ZPERMALINKURL, - ZSLKDEPRECATEDMESSAGE.ZCHANNELID, - ZSLKDEPRECATEDBASECHANNEL.ZTSID, - ZSLKDEPRECATEDBASECHANNEL.ZTSID1, - ZSLKDEPRECATEDCOREDATAUSER.ZTSID - from ZSLKDEPRECATEDMESSAGE, ZSLKDEPRECATEDBASECHANNEL,ZSLKDEPRECATEDCOREDATAUSER, ZSLKDEPRECATEDFILE - where ZSLKDEPRECATEDCOREDATAUSER.ZTSID = ZSLKDEPRECATEDMESSAGE.ZUSERID and - (ZSLKDEPRECATEDBASECHANNEL.ZTSID = ZSLKDEPRECATEDMESSAGE.ZCHANNELID or ZSLKDEPRECATEDBASECHANNEL.ZTSID1 = ZSLKDEPRECATEDMESSAGE.ZCHANNELID) and - HasSharedFile = ZSLKDEPRECATEDFILE.ZTSID - order by ZSLKDEPRECATEDMESSAGE.ZTIMESTAMP - ''') - else: - squery = (''' - select distinct - datetime(ZSLKMESSAGE.ZTIMESTAMP, 'unixepoch') as MessageTimeStamp, - ZSLKMESSAGE.ZUSERID as MessageGeneratedFrom, - ZSLKCOREDATAUSER.ZREALNAME as MessageGeneratedFromName, - ZSLKBASECHANNEL.ZNAME as MessageSentToChannelName, - ZSLKMESSAGE.ZTEXT, - json_extract(ZFILEIDS, '$[0]') as HasSharedFile, - ZSLKFILE.ZMODESTRING, - ZSLKFILE.ZTITLE, - ZSLKFILE.ZTYPESTRING, - datetime(ZSLKFILE.ZTIMESTAMP, 'unixepoch') as FileTimeStamp, - ZSLKFILE.ZPREVIEW, - ZSLKFILE.ZSIZE, - ZSLKFILE.ZPRIVATEDOWNLOADURL, - ZSLKFILE.ZPERMALINKURL, - ZSLKMESSAGE.ZCHANNELID, - ZSLKBASECHANNEL.ZTSID, - ZSLKBASECHANNEL.ZTSID1, - ZSLKCOREDATAUSER.ZTSID - from ZSLKMESSAGE, ZSLKBASECHANNEL,ZSLKCOREDATAUSER, ZSLKFILE - where ZSLKCOREDATAUSER.ZTSID = ZSLKMESSAGE.ZUSERID and - (ZSLKBASECHANNEL.ZTSID = ZSLKMESSAGE.ZCHANNELID or ZSLKBASECHANNEL.ZTSID1 = ZSLKMESSAGE.ZCHANNELID) and - HasSharedFile = ZSLKFILE.ZTSID - order by ZSLKMESSAGE.ZTIMESTAMP - ''') - - cursor.execute(squery) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], row[17] )) - - description = 'Slack Attachments' - report = ArtifactHtmlReport('Slack Attachments') - report.start_artifact_report(report_folder, 'Slack Attachments', description) - report.add_script() - data_headers = ('Timestamp', 'From', 'From Name', 'Channel Name', 'Message', 'Shared File', 'Mode', 'Title', 'Type', 'File Timestamp', 'Preview', 'Size', 'Private Download URL', 'Permalink URL', 'Channel ID','Channel SID', 'Channel SID1','User SID' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Slack Attachments' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Slack Attachments' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Slack User data available') - - if deprecated == 1: - squery = (''' - select - datetime(ZSLKDEPRECATEDBASECHANNEL.ZCREATED, 'unixepoch') as CreatedTime, - datetime(ZSLKDEPRECATEDBASECHANNEL.ZPURPOSELASTSET, 'unixepoch') as PurposeLastSet, - datetime(ZSLKDEPRECATEDBASECHANNEL.ZTOPICLASTSET, 'unixepoch') as TopicLastSet, - datetime(ZSLKDEPRECATEDBASECHANNEL.ZLATEST, 'unixepoch') as Latest, - ZSLKDEPRECATEDBASECHANNEL.ZNAME as ChannelNames, - ZSLKDEPRECATEDBASECHANNEL.ZTSID as DMChannels, - ZSLKDEPRECATEDBASECHANNEL.ZTSID1 as OtherChannels, - ZSLKDEPRECATEDBASECHANNEL.ZUSERID, - ZSLKDEPRECATEDBASECHANNEL.ZCREATORID, - ZSLKDEPRECATEDBASECHANNEL.ZPURPOSECREATORID, - ZSLKDEPRECATEDBASECHANNEL.ZPURPOSETEXT, - ZSLKDEPRECATEDBASECHANNEL.ZTOPICCREATORID, - ZSLKDEPRECATEDBASECHANNEL.ZTOPICTEXT - from ZSLKDEPRECATEDBASECHANNEL - ''') - else: - squery = (''' - select - datetime(ZSLKBASECHANNEL.ZCREATED, 'unixepoch') as CreatedTime, - datetime(ZSLKBASECHANNEL.ZPURPOSELASTSET, 'unixepoch') as PurposeLastSet, - datetime(ZSLKBASECHANNEL.ZTOPICLASTSET, 'unixepoch') as TopicLastSet, - datetime(ZSLKBASECHANNEL.ZLATEST, 'unixepoch') as Latest, - ZSLKBASECHANNEL.ZNAME as ChannelNames, - ZSLKBASECHANNEL.ZTSID as DMChannels, - ZSLKBASECHANNEL.ZTSID1 as OtherChannels, - ZSLKBASECHANNEL.ZUSERID, - ZSLKBASECHANNEL.ZCREATORID, - ZSLKBASECHANNEL.ZPURPOSECREATORID, - ZSLKBASECHANNEL.ZPURPOSETEXT, - ZSLKBASECHANNEL.ZTOPICCREATORID, - ZSLKBASECHANNEL.ZTOPICTEXT - from ZSLKBASECHANNEL - ''') - - cursor.execute(squery) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12] )) - - description = 'Slack Channel Data' - report = ArtifactHtmlReport('Slack Channel Data') - report.start_artifact_report(report_folder, 'Slack Channel Data', description) - report.add_script() - data_headers = ('Timestamp Created', 'Purpose Last Set', 'Topic Last Set', 'Latest', 'Channel Names','DM Channels', 'Other Channels', 'User ID', 'Creator ID', 'Purpose Creator ID', 'Purpose Text', 'Topic Creator ID', 'Topic Text' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Slack Channel Data' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Slack Channel Data' - timeline(report_folder, tlactivity, data_list, data_headers) - - - else: - logfunc('No Slack Channel Data available') - - if deprecated == 1: - squery = (''' - select - ZSLKDEPRECATEDTEAM.ZNAME, - ZSLKDEPRECATEDTEAM.ZDOMAIN, - ZSLKDEPRECATEDTEAM.ZAUTHUSERID, - ZSLKDEPRECATEDTEAM.ZTSID - from ZSLKDEPRECATEDTEAM - ''') - else: - squery = (''' - select - ZSLKTEAM.ZNAME, - ZSLKTEAM.ZDOMAIN, - ZSLKTEAM.ZAUTHUSERID, - ZSLKTEAM.ZTSID - from ZSLKTEAM - ''') - - cursor.execute(squery) - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3] )) - - description = 'Slack Team Data' - report = ArtifactHtmlReport('Slack Team Data') - report.start_artifact_report(report_folder, 'Slack Team Data', description) - report.add_script() - data_headers = ('Name', 'Domain Name', 'Author User ID', 'SID' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Team Data' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('No Slack Workspace Data available') - - - \ No newline at end of file diff --git a/scripts/artifacts/tcc.py b/scripts/artifacts/tcc.py deleted file mode 100644 index ef2085bb..00000000 --- a/scripts/artifacts/tcc.py +++ /dev/null @@ -1,60 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf -from packaging import version #use to search per version number - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - -def get_tcc(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('TCC.db'): - break - - db = open_sqlite_db_readonly(file_found) - iOSversion = scripts.artifacts.artGlobals.versionf - if version.parse(iOSversion) >= version.parse("9"): - cursor = db.cursor() - cursor.execute(''' - select client, - service, - datetime(last_modified,'unixepoch') - from access - order by client - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list =[] - for row in all_rows: - data_list.append((row[0], row[1], row[2])) - - if usageentries > 0: - report = ArtifactHtmlReport('TCC - Permissions') - report.start_artifact_report(report_folder, 'TCC - Permissions') - report.add_script() - data_headers = ('Bundle ID','Permissions','Last Modified Timestamp') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - ''' - tsvname = 'InteractionC Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'InteractonC Contacts' - timeline(report_folder, tlactivity, data_list, data_headers) - ''' - else: - logfunc('No data available in TCC database.') - - db.close() - return - - - \ No newline at end of file diff --git a/scripts/artifacts/teams.py b/scripts/artifacts/teams.py deleted file mode 100644 index 0bda65a9..00000000 --- a/scripts/artifacts/teams.py +++ /dev/null @@ -1,246 +0,0 @@ -import sqlite3 -import io -import json -import os -import re -import shutil -import datetime -import nska_deserialize as nd -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_teams(files_found, report_folder, seeker): - CacheFile = 0 - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - databasedata = file_found - if file_found.endswith('CacheFile'): - CacheFile = file_found - - if CacheFile != 0: - with open(CacheFile ,'rb') as nsfile: - nsplist = nd.deserialize_plist(nsfile) - - db = open_sqlite_db_readonly(databasedata) - cursor = db.cursor() - cursor.execute(''' - SELECT - datetime('2001-01-01', "ZARRIVALTIME" || ' seconds'), - ZIMDISPLAYNAME, - ZCONTENT - from ZSMESSAGE - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - thumb ='' - if '
' - data_list.append((row[0], row[1], row[2], thumb)) - - description = 'Teams Messages' - report = ArtifactHtmlReport('Teams Messages') - report.start_artifact_report(report_folder, 'Teams Messages', description) - report.add_script() - data_headers = ('Timestamp', 'Name', 'Message', 'Shared Media') - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Shared Media'] -) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Microsoft Teams Messages' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Microsoft Teams Messages data available') - - cursor.execute(''' - SELECT - ZDISPLAYNAME, - zemail, - ZPHONENUMBER - from - ZDEVICECONTACTHASH - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2])) - - description = 'Teams Contact' - report = ArtifactHtmlReport('Teams Contact') - report.start_artifact_report(report_folder, 'Teams Contact', description) - report.add_script() - data_headers = ('Display Name', 'Email', 'Phone Number') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Teams Contact' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('No Teams Contact data available') - - cursor.execute(''' - SELECT - datetime('2001-01-01', "ZTS_LASTSYNCEDAT" || ' seconds'), - ZDISPLAYNAME, - ZTELEPHONENUMBER - from zuser - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2])) - - description = 'Teams User' - report = ArtifactHtmlReport('Teams User') - report.start_artifact_report(report_folder, 'Teams User', description) - report.add_script() - data_headers = ('Timestamp Last Sync', 'Display Name', 'Phone Number') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams User' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Microsoft Teams User' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Teams User data available') - - cursor.execute(''' - SELECT - ZCOMPOSETIME, - zfrom, - ZIMDISPLAYNAME, - zcontent, - ZPROPERTIES - from ZSMESSAGE, ZMESSAGEPROPERTIES - where ZSMESSAGE.ZTSID = ZMESSAGEPROPERTIES.ZTSID - order by ZCOMPOSETIME - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list_calls = [] - data_list_cards = [] - data_list_unparsed = [] - - if usageentries > 0: - for row in all_rows: - plist = '' - composetime = row[0].replace('T',' ') - plist_file_object = io.BytesIO(row[4]) - if row[4].find(b'NSKeyedArchiver') == -1: - if sys.version_info >= (3, 9): - plist = plistlib.load(plist_file_object) - else: - plist = biplist.readPlist(plist_file_object) - else: - try: - plist = nd.deserialize_plist(plist_file_object) - except (nd.DeserializeError, nd.biplist.NotBinaryPlistException, nd.biplist.InvalidPlistException, - nd.plistlib.InvalidFileException, nd.ccl_bplist.BplistError, ValueError, TypeError, OSError, OverflowError) as ex: - logfunc(f'Failed to read plist for {row[4]}, error was:' + str(ex)) - if 'call-log' in plist: - datacalls = json.loads(plist['call-log']) - callstart = (datacalls.get('startTime')) - callstart = callstart.replace('T',' ') - callconnect = (datacalls.get('connectTime')) - callconnect = callconnect.replace('T',' ') - callend = (datacalls['endTime']) - callend = callend.replace('T',' ') - calldirection = (datacalls['callDirection']) - calltype = (datacalls['callType']) - callstate = (datacalls['callState']) - calloriginator = (datacalls['originator']) - calltarget = (datacalls['target']) - calloriginatordname = (datacalls['originatorParticipant']['displayName']) - callparticipantdname = (datacalls['targetParticipant']['displayName']) - data_list_calls.append((composetime, row[1], row[2], row[3], callstart, callconnect, callend, calldirection, calltype, callstate, calloriginator, calltarget, calloriginatordname, callparticipantdname)) - elif 'cards' in plist: - cards = json.loads(plist['cards']) - cardurl = (cards[0]['content']['body'][0]['selectAction']['url']) - cardtitle = (cards[0]['content']['body'][0]['selectAction']['title']) - cardtext = (cards[0]['content']['body'][1]['text']) - cardurl2 = (cards[0]['content']['body'][0]['url']) - if (cards[0]['content']['body'][0].get('id')) is not None: - idcontent = json.loads(cards[0]['content']['body'][0]['id']) - cardlat = (idcontent.get('latitude')) - cardlong = (idcontent.get('longitude')) - cardexpires = (idcontent.get('expiresAt')) - cardexpires = datetime.datetime.fromtimestamp(cardexpires / 1000) - carddevid = (idcontent.get('deviceId')) - data_list_cards.append((composetime, row[1], row[2], row[3], cardurl, cardtitle, cardtext, cardurl2, cardlat, cardlong, cardexpires, carddevid)) - else: - data_list_unparsed.append(composetime, row[1], row[2], row[3], plist) - - description = 'Microsoft Teams Call Logs' - report = ArtifactHtmlReport('Microsoft Teams Call Logs') - report.start_artifact_report(report_folder, 'Teams Call Logs', description) - report.add_script() - data_headers = ('Compose Timestamp', 'From', 'Display Name', 'Content',' Call Start', 'Call Connect', 'Call End', 'Call Direction', 'Call Type', 'Call State', 'Call Originator', 'Call Target', 'Call Originator Name', 'Call Participant Name') - report.write_artifact_data_table(data_headers, data_list_calls, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Call Logs' - tsv(report_folder, data_headers, data_list_calls, tsvname) - - tlactivity = 'Microsoft Teams Call Logs' - timeline(report_folder, tlactivity, data_list_calls, data_headers) - - description = 'Microsoft Teams Shared Locations' - report = ArtifactHtmlReport('Microsoft Teams Shared Locations') - report.start_artifact_report(report_folder, 'Teams Shared Locations', description) - report.add_script() - data_headers = ('Timestamp', 'From', 'Display Name', 'Content','Card URL', 'Card Title', 'Card Text', 'Card URL2', 'Latitude', 'Longitude', 'Card Expires', 'Device ID') - report.write_artifact_data_table(data_headers, data_list_cards, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Shared Locations' - tsv(report_folder, data_headers, data_list_cards, tsvname) - - tlactivity = 'Microsoft Teams Shared Locations' - timeline(report_folder, tlactivity, data_list_cards, data_headers) - - kmlactivity = 'Microsoft Teams Shared Locations' - kmlgen(report_folder, kmlactivity, data_list_cards, data_headers) - - else: - logfunc('No Microsoft Teams Call Logs & Cards data available') - - - db.close() - - - - \ No newline at end of file diff --git a/scripts/artifacts/teamsSegment.py b/scripts/artifacts/teamsSegment.py deleted file mode 100644 index 59e1d295..00000000 --- a/scripts/artifacts/teamsSegment.py +++ /dev/null @@ -1,139 +0,0 @@ -import json -import scripts.artifacts.artGlobals #use to get iOS version -> iOSversion = scripts.artifacts.artGlobals.versionf - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, timeline, kmlgen, tsv, is_platform_windows - -def get_teamsSegment(files_found, report_folder, seeker): - data_list_location = [] - data_list_motion = [] - data_list_timecheck = [] - data_list_power = [] - data_list_statechange = [] - - for file_found in files_found: - with open(file_found) as file: - for line in file: - serial = json.loads(line) - timestamp = serial[0].replace('T',' ') - #print(serial[1]) - if serial[1] == 'location': - locationtimestamp = serial[2]['sourceTimestamp'] - locationtimestamp = locationtimestamp.replace('T',' ') - longitude = serial[2]['longitude'] - latitude = serial[2]['latitude'] - speed = serial[2]['speed'] - altitude = serial[2]['altitude'] - vertacc = serial[2]['verticalAccuracy'] - horiacc = serial[2]['horizontalAccuracy'] - data_list_location.append((locationtimestamp, longitude, latitude, speed, altitude, vertacc, horiacc)) - - if serial[1] == 'motion': - motionact = (serial[2]['activityName']) - data_list_motion.append((timestamp, motionact)) - - if serial[1] == 'timeCheck': - tczone = serial[2]['timezone'] - tcoffset = serial[2]['offset'] - tcreason = serial[2]['reason'] - data_list_timecheck.append((timestamp, tczone, tcoffset, tcreason)) - - if serial[1] == 'power': - plugged = serial[2]['isPluggedIn'] - batlvl = serial[2]['batteryLevel'] - data_list_power.append((timestamp, plugged, batlvl)) - - if serial[1] == 'stateChange': - agg = ' ' - for a, b in serial[2].items(): - agg = agg + (f'{a}: {b} ') - agg = agg.lstrip() - data_list_statechange.append((timestamp, agg)) - - if len(data_list_location) > 0: - report = ArtifactHtmlReport('Microsoft Teams Locations') - report.start_artifact_report(report_folder, 'Teams Locations') - report.add_script() - data_headers_location = ('Timestamp', 'Longitude', 'Latitude', 'Speed', 'Altitude', 'Vertical Accuracy', 'Horizontal Accuracy') - report.write_artifact_data_table(data_headers_location, data_list_location, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Locations' - tsv(report_folder, data_headers_location, data_list_location, tsvname) - - tlactivity = 'Microsoft Teams Locations' - timeline(report_folder, tlactivity, data_list_location, data_headers_location) - - kmlactivity = 'Microsoft Teams Locations' - kmlgen(report_folder, kmlactivity, data_list_location, data_headers_location) - else: - logfunc('No Microsoft Teams Locations data') - - - if len(data_list_motion) > 0: - report = ArtifactHtmlReport('Microsoft Teams Motion') - report.start_artifact_report(report_folder, 'Teams Motion') - report.add_script() - data_headers_motion = ('Timestamp', 'Activity') - report.write_artifact_data_table(data_headers_motion, data_list_motion, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Motion' - tsv(report_folder, data_headers_motion, data_list_motion, tsvname) - - tlactivity = 'Microsoft Teams Motion' - timeline(report_folder, tlactivity, data_list_motion, data_headers_motion) - - else: - logfunc('No Microsoft Teams Motion data') - - if len(data_list_timecheck) > 0: - report = ArtifactHtmlReport('Microsoft Teams Timezone') - report.start_artifact_report(report_folder, 'Teams Timezone') - report.add_script() - data_headers_timecheck = ('Timestamp', 'Timezone', 'Timezone Offset', 'Timezone reason') - report.write_artifact_data_table(data_headers_timecheck, data_list_timecheck, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Timezone' - tsv(report_folder, data_headers_timecheck, data_list_timecheck, tsvname) - - tlactivity = 'Microsoft Teams Timezone' - timeline(report_folder, tlactivity, data_list_timecheck, data_headers_timecheck) - - else: - logfunc('No Microsoft Teams Timezone data') - - if len(data_list_power) > 0: - report = ArtifactHtmlReport('Microsoft Teams Power Log') - report.start_artifact_report(report_folder, 'Teams Power Log') - report.add_script() - data_headers_power = ('Timestamp', 'Is plugged in?', 'Battery Level') - report.write_artifact_data_table(data_headers_power, data_list_power, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams Power Log' - tsv(report_folder, data_headers_power, data_list_power, tsvname) - - tlactivity = 'Microsoft Teams Power Log' - timeline(report_folder, tlactivity, data_list_power, data_headers_power) - - else: - logfunc('No Microsoft Teams Power Log data') - - if len(data_list_statechange) > 0: - report = ArtifactHtmlReport('Microsoft Teams State Change') - report.start_artifact_report(report_folder, 'Teams State Change') - report.add_script() - data_headers_statechange = ('Timestamp', 'Change') - report.write_artifact_data_table(data_headers_statechange, data_list_statechange, file_found) - report.end_artifact_report() - - tsvname = 'Microsoft Teams State Change' - tsv(report_folder, data_headers_statechange, data_list_statechange, tsvname) - - tlactivity = 'Microsoft Teams State Change' - timeline(report_folder, tlactivity, data_list_statechange, data_headers_statechange) - - else: - logfunc('No Microsoft Teams Power State Change') \ No newline at end of file diff --git a/scripts/artifacts/textinputTyping.py b/scripts/artifacts/textinputTyping.py deleted file mode 100644 index bfcb426a..00000000 --- a/scripts/artifacts/textinputTyping.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -import nska_deserialize as nd -import json - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_textinputTyping(files_found, report_folder, seeker): - count = 0 - for file_found in files_found: - logfunc(str(file_found)) - count = count + 1 - data_list = [] - with open(file_found, 'rb') as f: - try: - deserialized_plist = nd.deserialize_plist(f) - #print(deserialized_plist) - except (nd.DeserializeError, - nd.biplist.NotBinaryPlistException, - nd.biplist.InvalidPlistException, - plistlib.InvalidFileException, - nd.ccl_bplist.BplistError, - ValueError, - TypeError, OSError, OverflowError) as ex: - # These are all possible errors from libraries imported - - print('Had exception: ' + str(ex)) - deserialized_plist = None - - lenofjson = len(deserialized_plist['alignedEntries']) - testrun = deserialized_plist['alignedEntries'][lenofjson -1] - for x, y in testrun['originalWord'].items(): - #print(x) - if x == 'documentState': - finalvalue = (y['contextBeforeInput']) - - if x == 'keyboardState': - for a, b in y.items(): - if a == 'inputContextHistory': - for c, d in b.items(): - if c == 'pendingEntries': - #print(d) #this is a list - for e in d: - data_list.append((e['timestamp'], e['senderIdentifier'], e['text'], '' )) - - data_list.append(('','', finalvalue, 'True')) - - - entries = len(data_list) - if entries > 0: - report = ArtifactHtmlReport('Text Input Typing') - report.start_artifact_report(report_folder, f'Messages {count}') - report.add_script() - data_headers = ('Timestamp','Sender Identifier','Text','contextBeforeInput' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = f'Messages {count}' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Messages {count}' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc(f"No Messages {count} available") - - \ No newline at end of file diff --git a/scripts/artifacts/tikTok.py b/scripts/artifacts/tikTok.py deleted file mode 100644 index 6c13adb0..00000000 --- a/scripts/artifacts/tikTok.py +++ /dev/null @@ -1,110 +0,0 @@ -from os.path import dirname, join -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def get_tikTok(files_found, report_folder, seeker): - data_list = [] - data_list1 = [] - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('db.sqlite'): - maindb = file_found - if file_found.endswith('AwemeIM.db'): - attachdb = file_found - - db = open_sqlite_db_readonly(maindb) - cursor = db.cursor() - cursor.execute(f"ATTACH DATABASE '{attachdb}' as AwemeIM;") - cursor.execute("SELECT name FROM AwemeIM.sqlite_master WHERE type='table' LIMIT 1;") - tablename = cursor.fetchall() - for rown in tablename: - tname = rown[0] - - cursor.execute(f''' - select - datetime(localcreatedat, 'unixepoch') as Local_Create_Time, - sender, - customid, - nickname, - json_extract(content, '$.text') as message, - json_extract(content, '$.tips') as localresponse, - json_extract(content,'$.display_name') as links_display_name, - json_extract(content, '$.url.url_list[0]') as links_gifs_urls, - case - when servercreatedat > 1 then datetime(servercreatedat, 'unixepoch') - else servercreatedat - end - servercreatedat, - url1 as profilepicURL - from TIMMessageORM, {tname} - where uid = sender - order by Local_Create_Time - ''') - - all_rows = cursor.fetchall() - - if len(all_rows) > 0: - for row in all_rows: - - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6],row[7], row[8], row[9])) - - report = ArtifactHtmlReport('TikTok Messages') - report.start_artifact_report(report_folder, 'TikTok Messages') - report.add_script() - data_headers = ('Timestamp','Sender','Custom ID','Nickname','Message', 'Local Response','Link GIF Name','Link GIF URL','Server Create Timestamps','Profile Pic URL') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Tiktok Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'TikTok Messages' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No TikTok messages available') - - cursor.execute(f''' - select - case - when latestchattimestamp > 1 then datetime(latestchattimestamp, 'unixepoch') - else latestchattimestamp - end - latestchattimestamp, - nickname, - uid, - customID, - url1 - from {tname} - ''') - - all_rows1 = cursor.fetchall() - - if len(all_rows) > 0: - description = 'Timestamp corresponds to latest chat if available' - for row in all_rows1: - - data_list1.append((row[0], row[1], row[2], row[3], row[4])) - - report = ArtifactHtmlReport('TikTok Contacts') - report.start_artifact_report(report_folder, 'TikTok Contacts', description) - report.add_script() - data_headers1 = ('Timestamp','Nickname','Unique ID','Custom ID','URL') - report.write_artifact_data_table(data_headers1, data_list1, file_found) - report.end_artifact_report() - - tsvname = 'TikTok Contacts' - tsv(report_folder, data_headers1, data_list1, tsvname) - - tlactivity = 'TikTok Last Contact' - timeline(report_folder, tlactivity, data_list1, data_headers1) - - else: - logfunc('No TikTok Contacts available') - - db.close() - \ No newline at end of file diff --git a/scripts/artifacts/tileApp.py b/scripts/artifacts/tileApp.py deleted file mode 100644 index e9645627..00000000 --- a/scripts/artifacts/tileApp.py +++ /dev/null @@ -1,58 +0,0 @@ -import gzip -import re -import os -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen,tsv, is_platform_windows - - -def get_tileApp(files_found, report_folder, seeker): - data_list = [] - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('gz'): - x=gzip.open - elif file_found.endswith('log'): - x=open - - counter = 0 - with x(file_found,'rt',) as f: - for line in f: - regexdate = r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.\d{3}" - datestamp = re.search(regexdate, line) - counter +=1 - if datestamp != None: - datestamp = datestamp.group(0) - regexlatlong = r"<[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)>" - latlong = re.search(regexlatlong, line) - if latlong != None: - latlong = latlong.group(0) - latlong = latlong.strip('<') - latlong = latlong.strip('>') - lat, longi = latlong.split(',') - head_tail = os.path.split(file_found) - data_list.append((datestamp, lat.lstrip(), longi.lstrip(), counter, head_tail[1])) - - if len(data_list) > 0: - description = 'Tile app log recorded langitude and longitude coordinates.' - report = ArtifactHtmlReport('Locations') - report.start_artifact_report(report_folder, 'Tile App Geolocation Logs', description) - report.add_script() - data_headers = ('Timestamp', 'Latitude', 'Longitude', 'Row Number', 'Source File' ) - report.write_artifact_data_table(data_headers, data_list, head_tail[0]) - report.end_artifact_report() - - tsvname = 'Tile App Lat Long' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Tile App Lat Long' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Tile App Lat Long' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - \ No newline at end of file diff --git a/scripts/artifacts/tileAppDb.py b/scripts/artifacts/tileAppDb.py deleted file mode 100644 index 74765650..00000000 --- a/scripts/artifacts/tileAppDb.py +++ /dev/null @@ -1,63 +0,0 @@ -import glob -import os -import pathlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, kmlgen, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_tileAppDb(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('tile-TileNetworkDB.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - datetime(ZTIMESTAMP,'unixepoch','31 years'), - ZNAME, - datetime(ZACTIVATION_TIMESTAMP,'unixepoch','31 years'), - datetime(ZREGISTRATION_TIMESTAMP,'unixepoch','31 years'), - ZALTITUDE, - ZLATITUDE, - ZLONGITUDE, - ZID, - ZNODE_TYPE, - ZSTATUS, - ZIS_LOST, - datetime(ZLAST_LOST_TILE_COMMUNITY_CONNECTION,'unixepoch','31 years') - FROM ZTILENTITY_NODE INNER JOIN ZTILENTITY_TILESTATE ON ZTILENTITY_NODE.ZTILE_STATE = ZTILENTITY_TILESTATE.Z_PK - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11])) - - description = '' - report = ArtifactHtmlReport('Tile App - Tile Information & Geolocation') - report.start_artifact_report(report_folder, 'Tile App DB Info & Geolocation', description) - report.add_script() - data_headers = ('Timestamp','Tile Name','Activation Timestamp','Registration Timestamp','Altitude','Latitude','Longitude','Tile ID','Tile Type','Status','Is Lost?','Last Community Connection' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Tile App DB Info Geolocation' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Tile App DB Info Geolocation' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Tile App DB Info Geolocation' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - else: - logfunc('No Tile App DB data available') - - db.close() - return diff --git a/scripts/artifacts/tileAppDisc.py b/scripts/artifacts/tileAppDisc.py deleted file mode 100644 index 4249b8d6..00000000 --- a/scripts/artifacts/tileAppDisc.py +++ /dev/null @@ -1,51 +0,0 @@ -import glob -import os -import pathlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_tileAppDisc(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('tile-DiscoveredTileDB.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - datetime(ZLAST_MODIFIED_TIMESTAMP,'unixepoch','31 years'), - ZTILE_UUID - FROM - ZTILENTITY_DISCOVEREDTILE - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1])) - - description = 'Tile IDs seen from other users' - report = ArtifactHtmlReport('Tile App - Discovered Tiles') - report.start_artifact_report(report_folder, 'Tile App Discovered Tiles', description) - report.add_script() - data_headers = ('Last Modified Timestamp','Tile UUID') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Tile App Discovered Tiles' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Tile Discovered Tiles' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Tile App Discovered Tiles data available') - - db.close() - return diff --git a/scripts/artifacts/tileAppNetDb.py b/scripts/artifacts/tileAppNetDb.py deleted file mode 100644 index 5cfef4b6..00000000 --- a/scripts/artifacts/tileAppNetDb.py +++ /dev/null @@ -1,53 +0,0 @@ -import glob -import os -import pathlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, is_platform_windows, open_sqlite_db_readonly - - -def get_tileAppNetDb(files_found, report_folder, seeker): - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('tile-TileNetworkDB.sqlite'): - break - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - datetime(ZREGISTRATION_TIMESTAMP,'unixepoch','31 years'), - ZEMAIL, - ZFULL_NAME, - ZMOBILE_PHONE - FROM - ZTILENTITY_USER - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - data_list = [] - if usageentries > 0: - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3])) - - description = '' - report = ArtifactHtmlReport('Tile App - Account Information') - report.start_artifact_report(report_folder, 'Tile App Account Information', description) - report.add_script() - data_headers = ('Registration Timestamp','Email','Full Name','Mobile Phone Number') - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Tile App Account Information' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Tile App Account Information' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Tile App DB account data available') - - db.close() - return diff --git a/scripts/artifacts/venmo.py b/scripts/artifacts/venmo.py deleted file mode 100644 index 90dfc0f6..00000000 --- a/scripts/artifacts/venmo.py +++ /dev/null @@ -1,177 +0,0 @@ -import nska_deserialize as nd -import plistlib -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly - - -def output_users(report_folder, transactions, filename): - """ - Outputs users info found through all transaction history - """ - if len(transactions) > 0: - report = ArtifactHtmlReport('Venmo - Users') - report.start_artifact_report(report_folder, 'Venmo - Users') - report.add_script() - data_headers = ( - 'User ID', 'Date Joined', 'Display Name', 'First Name', 'Last Name', 'Friend Status', 'Is Blocked', 'Is Active', 'Is Payable', - 'Identity Type', 'Profile Pic URL') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - users = {} - for row in transactions: - # Check actor - actor_date_joined = row.get('payment', {}).get('actor', {}).get('date_joined', 'UNKNOWN').replace('T', ' ').replace('Z', '') - actor_id = row.get('payment', {}).get('actor', {}).get('id', 'UNKNOWN') - actor_display_name =row.get('payment', {}).get('actor', {}).get('display_name', 'UNKNOWN') - actor_fname = row.get('payment', {}).get('actor', {}).get('first_name', 'UNKNOWN') - actor_lname = row.get('payment', {}).get('actor', {}).get('last_name', 'UNKNOWN') - actor_friend_status = row.get('payment', {}).get('actor', {}).get('friend_status', 'UNKNOWN') - actor_is_blocked = row.get('payment', {}).get('actor', {}).get('is_blocked', 'UNKNOWN') - actor_is_active = row.get('payment', {}).get('actor', {}).get('is_active', 'UNKNOWN') - actor_is_payable = row.get('payment', {}).get('actor', {}).get('is_payable', 'UNKNOWN') - actor_identity_type = row.get('payment', {}).get('actor', {}).get('identity_type', 'UNKNOWN') - actor_profile_pic_url = row.get('payment', {}).get('actor', {}).get('profile_picture_url', 'UNKNOWN') - - if users.get(actor_id, None) is None: - dict_to_add = [actor_date_joined, actor_display_name, actor_fname, actor_lname, actor_friend_status, - actor_is_blocked, actor_is_active, actor_is_payable, actor_identity_type, actor_profile_pic_url] - users[actor_id] = dict_to_add - x = 0 - - # Check target - target_date_joined = row.get('payment', {}).get('target', {}).get('user', {}).get('date_joined','UNKNOWN').replace('T',' ').replace('Z', '') - target_id = row.get('payment', {}).get('target', {}).get('user', {}).get('id', 'UNKNOWN') - target_display_name = row.get('payment', {}).get('target', {}).get('user', {}).get('display_name','UNKNOWN') - target_fname = row.get('payment', {}).get('target', {}).get('user', {}).get('first_name', 'UNKNOWN') - target_lname = row.get('payment', {}).get('target', {}).get('user', {}).get('last_name', 'UNKNOWN') - target_friend_status = row.get('payment', {}).get('target', {}).get('user', {}).get('friend_status', 'UNKNOWN') - target_is_blocked = row.get('payment', {}).get('target', {}).get('user', {}).get('is_blocked', 'UNKNOWN') - target_is_active = row.get('payment', {}).get('target', {}).get('user', {}).get('is_active', 'UNKNOWN') - target_is_payable = row.get('payment', {}).get('target', {}).get('user', {}).get('is_payable', 'UNKNOWN') - target_identity_type = row.get('payment', {}).get('target', {}).get('user', {}).get('identity_type', 'UNKNOWN') - target_profile_pic_url = row.get('payment', {}).get('target', {}).get('user', {}).get('profile_picture_url', - 'UNKNOWN') - - if users.get(target_id, None) is None: - dict_to_add = [target_date_joined, target_display_name, target_fname, target_lname, target_friend_status, - target_is_blocked, target_is_active, target_is_payable, target_identity_type, target_profile_pic_url] - users[target_id] = dict_to_add - - for user in users: - data_list.append((user, users[user][0], users[user][1], users[user][2], users[user][3], users[user][4], - users[user][5], users[user][6], users[user][7], users[user][8], users[user][9])) - - report.write_artifact_data_table(data_headers, data_list, filename) - report.end_artifact_report() - - tsvname = f'Venmo - Users' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Venmo - Users' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Venmo - Users data available') - -def output_transactions(report_folder, transactions, filename): - """ - Outputs transaction history - """ - - if len(transactions) > 0: - report = ArtifactHtmlReport('Venmo - Transactions') - report.start_artifact_report(report_folder, 'Venmo - Transactions') - report.add_script() - data_headers = ( - 'Date Created', 'Date Completed', 'Action', 'Payer', 'Payer ID', 'Receiver', 'Receiver ID', 'Note', 'Amount', 'Status', 'Audience', 'Type', 'Context') # Don't remove the comma, that is required to make this a tuple as there is only 1 element - data_list = [] - for row in transactions: - - if row['type'] == 'disbursement': - pass - if row['type'] == 'payment': - - if row['payment']['type'] == 'payment': - t_created = row.get('date_created', 'UNKNOWN').replace('T', ' ').replace('Z', '') - t_completed = row.get('payment', {}).get('date_completed', 'N/A').replace('T', ' ').replace('Z', '') - ptype = row.get('type', 'UNKNOWN') - action = row.get('payment', {}).get('action', 'UNKNOWN') - - note = row.get('payment', {}).get('note', 'UNKNOWN') - amount = row.get('payment', {}).get('amount', 'UNKNOWN') - status =row.get('payment', {}).get('status', 'UNKNOWN') - audience = row.get('audience', 'UNKNOWN') - - #Make the context sentence for easier understanding + logic for payer vs receiver - if action == 'charge': - receiver = row.get('payment', {}).get('actor', {}).get('display_name', 'UNKNOWN') - receiver_id = row.get('payment', {}).get('actor', {}).get('username', 'UNKNOWN') - payer = row.get('payment', {}).get('target', {}).get('user', {}).get('display_name', 'UNKNOWN') - payer_id = row.get('payment', {}).get('target', {}).get('user', {}).get('username', 'UNKNOWN') - if amount == "UNKNOWN": - context = f'{receiver} charged {payer}' - else: - context = f'{receiver} charged {payer} {amount}' - - if action == 'pay': - payer = row.get('payment', {}).get('actor', {}).get('display_name', 'UNKNOWN') - payer_id = row.get('payment', {}).get('actor', {}).get('username', 'UNKNOWN') - receiver = row.get('payment', {}).get('target', {}).get('user', {}).get('display_name', 'UNKNOWN') - receiver_id = row.get('payment', {}).get('target', {}).get('user', {}).get('username', 'UNKNOWN') - if amount == "UNKNOWN": - context = f'{payer} paid {receiver}' - else: - context = f'{payer} paid {receiver} {amount}' - - elif row['type'] != 'payment' and row['type'] != 'disbursement': - logfunc(f'Unknown transaction type of \"{row["type"]}\" found!!') - data_list.append((t_created, t_completed, action, payer, payer_id, receiver, receiver_id, note, amount, status, audience, ptype, context)) - - - report.write_artifact_data_table(data_headers, data_list, filename) - report.end_artifact_report() - - tsvname = f'Venmo - Transactions' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Venmo - Transactions' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Venmo - Transactions data available') - -def deserialize_plist(plist_path): - """ - Use nska_deserialize to deserialize our plists - Goes right off of: https://pypi.org/project/nska-deserialize/ - """ - with open(plist_path, 'rb') as f: - try: - deserialized_plist = nd.deserialize_plist(f) - except (nd.DeserializeError, - nd.biplist.NotBinaryPlistException, - nd.biplist.InvalidPlistException, - plistlib.InvalidFileException, - nd.ccl_bplist.BplistError, - ValueError, - TypeError, OSError, OverflowError) as ex: - # These are all possible errors from libraries imported - - deserialized_plist = None - - return deserialized_plist - -def get_venmo(files_found, report_folder, seeker): - """ - Parse venmo transactions. It's pretty simply stored in a serialized plist, but an awesome resource for learning more is: - https://thebinaryhick.blog/2019/11/07/venmo-the-app-for-virtual-ballers/ - """ - - transaction_data = [] - - # Loop through files and deserialize - for filename in files_found: - deserialized_feed = deserialize_plist(filename) - if deserialized_feed is not None: - for row in deserialized_feed.get('stories', []): transaction_data.append(row) - - filenames = '\n'.join(files_found) - output_transactions(report_folder, transaction_data, filenames) - output_users(report_folder, transaction_data, filenames) diff --git a/scripts/artifacts/viber.py b/scripts/artifacts/viber.py deleted file mode 100644 index c434e631..00000000 --- a/scripts/artifacts/viber.py +++ /dev/null @@ -1,693 +0,0 @@ -# Get Viber settings, contacts, recent calls and messages information -# Author : Evangelos Dragonas (@theAtropos4n6) -# website : atropos4n6.com -# Date : 2022-03-15 -# Version : 0.0.2 -# -# The script queries Settings.data and Contacts.data Viber dbs and creates a report of findings including KML geolcation data -# Settings hold the user's personal data and configurations -# Contacts hold contacts, calls, messages and more.. -# -# The code is divided in 4 queries-artifacts blocks. -# -# The 1st parses settings db, extracts and reports on user's available information regarding Viber configuartion -# -# The 2nd parses contacts db, extracts and reports on user's contacts. -# Be advised that a contact may not participate in a chat (therefore a contact is not a chat 'member') and vice versa. A chat 'member' may not be registered as a Viber contact. -# Hope it makes sense. -# -# The 3rd parses contacts db, extracts and reports on user's recent calls that have no corresponding message (ZVIBERMESSAGE) entry. This indicates that these messages have been deleted and therefore -# calls are deleted as well. Unfortunately no remote partner information can be retrieved at this moment. -# -# The 4rth parses contacts db, extracts and reports on user's chats. 2 extra columns with each chat's grouped participants and phone numbers is also available. -# -# Also, be aware that there is more information stored within the above databases. This artifact assist in parsing the most out of it (but not all). -# -# Should you face a bug or want a specific field extracted, DM me. -# - - -import glob -import os -import pathlib -import sqlite3 -import json - -import scripts.artifacts.artGlobals -from packaging import version -from html import escape -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen, tsv, is_platform_windows, open_sqlite_db_readonly, media_to_html - - -def get_viber(files_found, report_folder, seeker): - viber_settings = {} - for file_found in files_found: - file_found = str(file_found) - - iOSversion = scripts.artifacts.artGlobals.versionf - if version.parse(iOSversion) < version.parse("14"): - logfunc("Viber parsing has not be tested on this iOS " + iOSversion + " version. Please contact @theAtropos4n6 for resolving this issue.") - - if version.parse(iOSversion) >= version.parse("14"): - if file_found.endswith('Settings.data'): - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - Data.key,value - FROM Data - WHERE Data.key IN - ( - '_myUserName', - '_currentEmail', - '_myPhoneNumber', - '_myCanonizedPhoneNumber', - '_myFormattedPhoneNumber', - '_myCountryPhoneCode', - '_myCountryCode', - '_myLanguageCode', - '_wasabiLastKnownUserLocation', - '_uid', - '_appVersion', - '_savedDeviceId', - '_attemptsToDownloadBackupForRestore', - '_backupAttemptsCount', - '_hiddenChatsPINData', - '_myPhotoLocalID' - ) - UNION - SELECT - Data.key, - CASE - WHEN value LIKE '-%' THEN value - ELSE datetime(value,'unixepoch') - END - FROM Data - WHERE Data.key IN - ('_registrationDate', - '_autoBackupLastRunTime', - '_lastBackupStartDate') - UNION - SELECT - Data.key, - datetime(value,'unixepoch') -- this value is stored in the user localtime - FROM Data - WHERE Data.key IS '_birthdate' - ORDER BY value - ''') - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list =[] - for row in all_rows: - viber_settings[row[0]] = row[1] - temp_list = list(row) - if temp_list[0] == '_appVersion': - temp_list[0] = 'Application Version' - elif temp_list[0] == '_lastBackupStartDate': - temp_list[0] = 'Last Backup Start Date - UTC' - elif temp_list[0] == '_myUserName': - temp_list[0] = 'User Name' - elif temp_list[0] == '_currentEmail': - temp_list[0] = 'Current Email' - elif temp_list[0] == '_birthdate': - temp_list[0] = "Birth Date - UTC (apply user's localtime offset)" - elif temp_list[0] == '_registrationDate': - temp_list[0] = 'Registration Date - UTC' - elif temp_list[0] == '_uid': - temp_list[0] = 'User ID' - elif temp_list[0] == '_myPhoneNumber': - temp_list[0] = 'Phone Number' - elif temp_list[0] == '_myCanonizedPhoneNumber': - temp_list[0] = 'Canonized Phone Number' - elif temp_list[0] == '_myFormattedPhoneNumber': - temp_list[0] = 'Formatted Phone Number' - elif temp_list[0] == '_myCountryPhoneCode': - temp_list[0] = 'Country Phone Code' - elif temp_list[0] == '_myCountryCode': - temp_list[0] = 'Country Code' - elif temp_list[0] == '_myLanguageCode': - temp_list[0] = 'Language Code' - elif temp_list[0] == '_wasabiLastKnownUserLocation': - temp_list[0] = 'Last Known User Location' - elif temp_list[0] == '_savedDeviceId': - temp_list[0] = 'Device ID' - elif temp_list[0] == '_myPhotoLocalID': - temp_list[0] = 'Profile Picture' - try: - if temp_list[1] is not None: - thumb = media_to_html(temp_list[1], files_found, report_folder) - temp_list[1] = thumb - else: - thumb = '' - except: - pass - elif temp_list[0] == '_attemptsToDownloadBackupForRestore': - temp_list[0] = 'Attempts To Download Backup For Restore' - try: - int.from_bytes(temp_list[1], byteorder='big') #needs further validation about the byteorder - except Exception as err: - logfunc(f'Viber - Settings "_attemptsToDownloadBackupForRestore" could not be extracted. The error was: {err}' ) - elif temp_list[0] == '_backupAttemptsCount': - temp_list[0] = 'Backup Attempts Count' - try: - int.from_bytes(temp_list[1], byteorder='big') #needs further validation about the byteorder - except Exception as err: - logfunc(f'Viber - Settings "_backupAttemptsCount" could not be extracted. The error was: {err}' ) - elif temp_list[0] == '_autoBackupLastRunTime': - temp_list[0] = 'Auto Backup Last Run Time - UTC' - x = str(temp_list[1]) - if x.startswith("-"): - temp_list[1] = 'Not Applied' - elif temp_list[0] == '_lastBackupStartDate': - x = str(temp_list[1]) - if x.startswith("-"): - temp_list[1] = 'Not Applied' - elif temp_list[0] == '_hiddenChatsPINData': - temp_list[0] = 'Hidden Chats PIN Data' - row = tuple(temp_list) - data_list.append((row[0], row[1])) - - - if usageentries > 0: - report = ArtifactHtmlReport('Viber - Settings') - report.start_artifact_report(report_folder, 'Viber - Settings') - report.add_script() - data_headers = ('Setting','Value') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - tsvname = 'Viber - Settings' - tsv(report_folder, data_headers, data_list, tsvname) - - db.close() - - elif file_found.endswith('Contacts.data'): - - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - - cursor.execute(''' - SELECT - ZABCONTACT.ZMAINNAME AS 'Main Name', - ZABCONTACT.ZPREFIXNAME AS 'Prefix Name', - ZABCONTACT.ZSUFFIXNAME AS 'Suffix Name', - ZABCONTACTNUMBER.ZPHONE AS 'Phone Number', - ZABCONTACTNUMBER.ZCANONIZEDPHONENUM AS 'Canonized Phone Number', - ZABCONTACT.ZCONTACTID AS 'Contact ID' - FROM ZABCONTACT - LEFT JOIN ZABCONTACTNUMBER ON ZABCONTACT.Z_PK = ZABCONTACTNUMBER.ZCONTACT - UNION - SELECT - ZABCONTACT.ZMAINNAME AS 'Main Name', - ZABCONTACT.ZPREFIXNAME AS 'Prefix Name', - ZABCONTACT.ZSUFFIXNAME AS 'Suffix Name', - ZABCONTACTNUMBER.ZPHONE AS 'Phone Number', - ZABCONTACTNUMBER.ZCANONIZEDPHONENUM AS 'Canonized Phone Number', - ZABCONTACT.ZCONTACTID AS 'Contact ID' - FROM ZABCONTACTNUMBER - LEFT JOIN ZABCONTACT ON ZABCONTACT.Z_PK = ZABCONTACTNUMBER.ZCONTACT - ORDER BY ZMAINNAME - ''') - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list =[] - for row in all_rows: - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5])) - - - if usageentries > 0: - report = ArtifactHtmlReport('Viber - Contacts') - report.start_artifact_report(report_folder, 'Viber - Contacts') - report.add_script() - data_headers = ('Main Name','Prefix Name','Suffix Name','Phone Number','Canonized Phone Number','Contact ID') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - - tsvname = 'Viber - Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - cursor.execute(''' - SELECT - datetime(ZRECENT.ZDATE+ 978307200,'unixepoch') AS 'Timestamp - UTC', - ZRECENT.ZRECENTSLINE AS 'EMPTY DUMMY COLUMN', - CASE - WHEN ZRECENT.ZCALLTYPE = 'missed' THEN 'Missed Audio Call' - WHEN ZRECENT.ZCALLTYPE = 'missed_with_video' THEN 'Missed Video Call' - WHEN ZRECENT.ZCALLTYPE = 'outgoing_viber' THEN 'Outgoing Audio Call' - WHEN ZRECENT.ZCALLTYPE = 'outgoing_viber_with_video' THEN 'Outgoing Video Call' - WHEN ZRECENT.ZCALLTYPE = 'incoming_with_video' THEN 'Incoming Video Call' - WHEN ZRECENT.ZCALLTYPE = 'incoming' THEN 'Incoming Audio Call' - ELSE ZRECENT.ZCALLTYPE - end AS 'Call Type', - ZRECENT.ZDURATION AS 'Duration' - FROM ZRECENT - WHERE ZRECENT.ZCALLLOGMESSAGE IS NULL AND ZRECENT.ZRECENTSLINE IS NULL - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list =[] - for row in all_rows: - temp_list = list(row) - try: - if 'Outgoing' in temp_list[2]: - temp_list[1] = str(viber_settings['_myUserName']) + ',' + str(viber_settings['_myPhoneNumber']) - except TypeError: - pass - row = tuple(temp_list) - data_list.append((row[0], row[1], row[2], row[3])) - - - - if usageentries > 0: - report = ArtifactHtmlReport('Viber - Call Remnants') - report.start_artifact_report(report_folder, 'Viber - Call Remnants') - report.add_script() - data_headers = ('Timestamp - UTC','Caller','Call Type','Duration') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - - cursor.execute(''' - SELECT - CHAT_MEMBER.ZDISPLAYFULLNAME AS 'Sender (Display Full Name)', - CHAT_MEMBER.ZDISPLAYSHORTNAME AS 'Sender (Display Short Name)', - CHAT_MEMBER.ZPHONE AS 'Sender (Phone)', - CHATS.Chat_Name AS 'Chat Name', - CHATS.CHAT_MEMBERS AS 'Chat Participant(s)', - CHATS.CHAT_PHONES 'Chat Phone(s)', - datetime(ZVIBERMESSAGE.ZSTATEDATE+ 978307200,'unixepoch') AS 'Message Creation Date - UTC', - datetime(ZVIBERMESSAGE.ZDATE+ 978307200,'unixepoch') AS 'Message Change State Date - UTC', - datetime(RECENT.ZRECENTDATE+ 978307200,'unixepoch') AS 'Call Date - UTC', - CASE - WHEN ZCALLTYPE = 'missed' THEN 'Missed Audio Call' - WHEN ZCALLTYPE = 'missed_with_video' THEN 'Missed Video Call' - WHEN ZCALLTYPE = 'outgoing_viber' THEN 'Outgoing Audio Call' - WHEN ZCALLTYPE = 'outgoing_viber_with_video' THEN 'Outgoing Video Call' - WHEN ZCALLTYPE = 'incoming_with_video' THEN 'Incoming Video Call' - WHEN ZCALLTYPE = 'incoming' THEN 'Incoming Audio Call' - ELSE ZCALLTYPE - end AS 'Call Type', - CASE - WHEN ZVIBERMESSAGE.ZSTATE IN ('send','delivered') THEN 'Outgoing' - WHEN ZVIBERMESSAGE.ZSTATE = 'received' THEN 'Incoming' - ELSE ZVIBERMESSAGE.ZSTATE - END AS 'State', - RECENT.ZDURATION AS 'Duration', - ZVIBERMESSAGE.ZSYSTEMTYPE 'System Type Description', - ZVIBERMESSAGE.ZMETADATA AS 'Message Metadata', - ZVIBERMESSAGE.ZTEXT AS 'Message Content', - ZATTACHMENT.ZNAME AS 'Attachment Name', - ZATTACHMENT.ZTYPE AS 'Attachment Type', - ZATTACHMENT.ZFILESIZE AS 'Attachment Size', - ZVIBERLOCATION.ZLATITUDE AS 'Latitude', - ZVIBERLOCATION.ZLONGITUDE AS 'Longitude', - CASE - WHEN CHATS.Chat_Deleted = 1 THEN 'True' - WHEN CHATS.Chat_Deleted = 0 THEN 'False' - ELSE CHATS.Chat_Deleted - END AS 'Conversation Deleted', - CASE - WHEN ZVIBERMESSAGE.ZBEINGDELETED = 1 THEN 'True' - WHEN ZVIBERMESSAGE.ZBEINGDELETED = 0 THEN 'False' - ELSE ZVIBERMESSAGE.ZBEINGDELETED - END AS 'Message Deleted', - CHATS.ZTIMEBOMBDURATION AS 'Conversation Time Bomb Duration', - ZVIBERMESSAGE.ZTIMEBOMBDURATION AS 'Message Time Bomb Duration', - datetime(ZVIBERMESSAGE.ZTIMEBOMBTIMESTAMP+ 978307200,'unixepoch') AS 'Message Time Bomb Timestamp', - CASE - WHEN CHATS.Chat_Favorite= 1 THEN 'True' - WHEN CHATS.Chat_Favorite = 0 THEN 'False' - ELSE CHATS.Chat_Favorite - END AS 'Conversation Marked Favorite', - ZVIBERMESSAGE.ZLIKESCOUNT AS 'Likes Count' - FROM - ZVIBERMESSAGE - LEFT JOIN - (SELECT - ZVIBERMESSAGE.ZCONVERSATION, - ZCONVERSATION.ZNAME AS 'Chat_Name', - ZCONVERSATION.ZBEINGDELETED AS 'Chat_Deleted', - ZCONVERSATION.ZFAVORITE AS 'Chat_Favorite', - ZCONVERSATION.ZTIMEBOMBDURATION, - coalesce(ZVIBERMESSAGE.ZPHONENUMINDEX,ZCONVERSATION.ZINTERLOCUTOR) AS 'MEMBER_ID', - MEMBER.ZDISPLAYFULLNAME, - MEMBER.ZDISPLAYSHORTNAME, - MEMBER.ZNAME AS 'Participant_Name', - MEMBER.ZCANONIZEDPHONENUM, - MEMBER.ZPHONE, - group_concat(DISTINCT(MEMBER.ZDISPLAYFULLNAME)) AS 'CHAT_MEMBERS', - group_concat(DISTINCT(MEMBER.ZPHONE)) AS 'CHAT_PHONES', - group_concat(DISTINCT(MEMBER.ZCANONIZEDPHONENUM)) AS 'CHAT_CANONIZED_PHONES' - FROM ZVIBERMESSAGE,ZCONVERSATION - LEFT JOIN - (SELECT - ZMEMBER.ZDISPLAYFULLNAME, - ZMEMBER.ZDISPLAYSHORTNAME, - ZMEMBER.ZNAME, - ZPHONENUMBER.ZCANONIZEDPHONENUM, - ZPHONENUMBER.ZPHONE, - ZMEMBER.Z_PK - FROM ZMEMBER - LEFT JOIN ZPHONENUMBER ON ZMEMBER.Z_PK = ZPHONENUMBER.ZMEMBER - UNION - SELECT - ZMEMBER.ZDISPLAYFULLNAME, - ZMEMBER.ZDISPLAYSHORTNAME, - ZMEMBER.ZNAME, - ZPHONENUMBER.ZCANONIZEDPHONENUM, - ZPHONENUMBER.ZPHONE, - ZMEMBER.Z_PK - FROM ZPHONENUMBER - LEFT JOIN ZMEMBER ON ZPHONENUMBER.ZMEMBER = ZMEMBER.Z_PK - ) AS MEMBER ON MEMBER.Z_PK = MEMBER_ID - LEFT JOIN ZPHONENUMBER ON MEMBER_ID = ZPHONENUMBER.ZMEMBER - WHERE ZVIBERMESSAGE.ZCONVERSATION = ZCONVERSATION.Z_PK - GROUP BY ZVIBERMESSAGE.ZCONVERSATION - ) CHATS ON ZVIBERMESSAGE.ZCONVERSATION = CHATS.ZCONVERSATION - - LEFT JOIN - (SELECT - ZMEMBER.ZDISPLAYFULLNAME, - ZMEMBER.ZDISPLAYSHORTNAME, - ZMEMBER.ZNAME, - ZPHONENUMBER.ZCANONIZEDPHONENUM, - ZPHONENUMBER.ZPHONE, - ZMEMBER.Z_PK - FROM ZMEMBER - LEFT JOIN ZPHONENUMBER ON ZMEMBER.Z_PK = ZPHONENUMBER.ZMEMBER - UNION - SELECT - ZMEMBER.ZDISPLAYFULLNAME, - ZMEMBER.ZDISPLAYSHORTNAME, - ZMEMBER.ZNAME, - ZPHONENUMBER.ZCANONIZEDPHONENUM, - ZPHONENUMBER.ZPHONE, - ZMEMBER.Z_PK - FROM ZPHONENUMBER - LEFT JOIN ZMEMBER ON ZPHONENUMBER.ZMEMBER = ZMEMBER.Z_PK - ) AS CHAT_MEMBER ON ZVIBERMESSAGE.ZPHONENUMINDEX = CHAT_MEMBER.Z_PK - LEFT JOIN - (SELECT - ZRECENT.ZDURATION, - ZRECENT.ZCALLLOGMESSAGE, - ZRECENT.ZDATE AS 'ZRECENTDATE', - ZRECENTSLINE.ZDATE AS 'ZRECENTSLINEDATE', - ZRECENT.ZCALLTYPE AS 'CALL TYPE', - ZRECENTSLINE.ZCALLTYPE AS 'CALL TYPE', - ZRECENTSLINE.ZPHONENUMBER AS 'PHONE NUMBER' - FROM ZRECENT - LEFT JOIN ZRECENTSLINE ON ZRECENT.ZRECENTSLINE = ZRECENTSLINE.Z_PK - ) AS RECENT ON ZVIBERMESSAGE.Z_PK = RECENT.ZCALLLOGMESSAGE - LEFT JOIN ZVIBERLOCATION ON ZVIBERMESSAGE.ZLOCATION = ZVIBERLOCATION.Z_PK - LEFT JOIN ZATTACHMENT ON ZVIBERMESSAGE.ZATTACHMENT = ZATTACHMENT.Z_PK - - ORDER BY ZVIBERMESSAGE.Z_PK - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list =[] - for row in all_rows: - temp_list = list(row) - temp_chats_names = str(temp_list[4]) - temp_list[4] = temp_chats_names + ',' + str(viber_settings['_myUserName']) - temp_chats_phones = str(temp_list[5]) - temp_list[5] = temp_chats_phones + ',' + str(viber_settings['_myPhoneNumber']) - if temp_list[13]: - y = json.loads(temp_list[13], strict=False) # the key that stores geolocation data is ['pa_message_data']['rich_media']['Buttons'][2]['Map'] - #if the 'Map' key is identified successfully it will assign lat,lon to the corresponding columns, otherwise it will continue on (passing any key,index errors) - temp_list[13] = '' - try: - temp_list[18] = y['pa_message_data']['rich_media']['Buttons'][2]['Map']['Latitude'] - temp_list[19] = y['pa_message_data']['rich_media']['Buttons'][2]['Map']['Longitude'] - except (KeyError,IndexError) as e: - pass - - #What this ugly long list of dict keys simply does is that it extracts only specific fields identified as important from the whole dictionary. - #The reason why we extract only specific fields is because the report is much prettier. In order to have a complete picture you will have to go through the whole dictionary - #while inspecting the .db itself. Therefore this column is named as 'Message Metadata Fragments' - - #general values - if "Text" in y: - try: - temp_list[13] += "Text: "+ str(y['Text'])+"," - except KeyError: - pass - if "Title" in y: - try: - temp_list[13] += "Title: "+ str(y['Title'])+"," - except KeyError: - pass - if "URL" in y: - try: - temp_list[13] += "URL: "+ str(y['URL'])+"," - except KeyError: - pass - if "ThumbnailURL" in y: - try: - temp_list[13] += "ThumbnailURL: "+ str(y['ThumbnailURL'])+"," - except KeyError: - pass - if "Type" in y: - try: - temp_list[13] += "Type: "+ str(y['Type'])+"," - except KeyError: - pass - - if "generalFwdInfo" in y: - try: - temp_list[13] += "Original Chat ID: "+ str(y['generalFwdInfo']['orig_chat_id'])+"," - except KeyError: - pass - - if "audio_ptt" in y: - try: - temp_list[13] += "Audio Duration: "+ str(y['audio_ptt']['duration'])+"," - except KeyError: - pass - - #fileInfo values - if "fileInfo" in y: - try: - temp_list[13] += "File Info - Content Type: "+ str(y['fileInfo']['ContentType'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Type: "+ str(y['fileInfo']['Type'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Hash: "+ str(y['fileInfo']['FileHash'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Name: "+ str(y['fileInfo']['FileName'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Extension: "+ str(y['fileInfo']['FileExt'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Duration: "+ str(y['fileInfo']['Duration'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Size: "+ str(y['fileInfo']['FileSize'])+"," - except KeyError: - pass - try: - temp_list[13] += "File Info - Original Size: "+ str(y['fileInfo']['OrigSize'])+"," - except KeyError: - pass - try: - temp_list[13] += "File|Media Info - iOS Origin: "+ str(y['fileInfo']['mediaInfo']['ios_origin'])+"," - except KeyError: - pass - try: - temp_list[13] += "File|Media Info - Width: "+ str(y['fileInfo']['mediaInfo']['Width'])+"," - except KeyError: - pass - try: - temp_list[13] += "File|Media Info - Height: "+ str(y['fileInfo']['mediaInfo']['Height'])+"," - except KeyError: - pass - try: - temp_list[13] += "File|Media Info - Media Type: "+ str(y['fileInfo']['mediaInfo']['MediaType'])+"," - except KeyError: - pass - - #custom_sticker_info values - if "custom_sticker_info" in y: - try: - temp_list[13] += "Custom Sticker Info - Package ID: "+ str(y['custom_sticker_info']['package_id'])+"," - except KeyError: - pass - try: - temp_list[13] += "Custom Sticker Info - Sticker ID: "+ str(y['custom_sticker_info']['sticker_id'])+"," - except KeyError: - pass - - #groupReferralInfo values - if "groupReferralInfo" in y: - try: - temp_list[13] += "Group ID: "+ str(y['groupReferralInfo']['groupID'])+"," - except KeyError: - pass - try: - temp_list[13] += "Group Name: "+ str(y['groupReferralInfo']['groupName'])+"," - except KeyError: - pass - try: - temp_list[13] += "Invite Link: "+ str(y['groupReferralInfo']['inviteLink'])+"," - except KeyError: - pass - - #pa_message_data values - if "pa_message_data" in y: - try: - temp_list[13] += "Message Data - Text: "+ str(y['pa_message_data']['text'])+"," - except KeyError: - pass - try: - temp_list[13] += "Message Data - Sender Name: "+ str(y['pa_message_data']['sender']['name'])+"," - except KeyError: - pass - try: - temp_list[13] += "Message Data - Alt Text: "+ str(y['pa_message_data']['alt_text'])+"," - except KeyError: - pass - try: - temp_list[13] += "Message Data - Favorites Metadata - URL: "+ str(y['pa_message_data']['rich_media']['FavoritesMetadata']['url'])+"," - except KeyError: - pass - - #pin values - if "pin" in y: - try: - temp_list[13] += "Pin - Action: "+ str(y['pin']['action'])+"," - except KeyError: - pass - try: - temp_list[13] += "Pin - Text: "+ str(y['pin']['text'])+"," - except KeyError: - pass - try: - temp_list[13] += "Pin - Description: "+ str(y['pin']['extended']['descr'])+"," - except KeyError: - pass - - #poll values - if "poll" in y: - try: - temp_list[13] += "Poll - Group ID: "+ str(y['poll']['groupID'])+"," - except KeyError: - pass - try: - temp_list[13] += "Poll - Type: "+ str(y['poll']['type'])+"," - except KeyError: - pass - try: - temp_list[13] += "Poll - Sender ID: "+ str(y['poll']['senderID'])+"," - except KeyError: - pass - try: - temp_list[13] += "Poll - Multiple: "+ str(y['poll']['multiple'])+"," - except KeyError: - pass - try: - temp_list[13] += "Poll - Quiz Text: "+ str(y['poll']['quiz_text'])+"," - except KeyError: - pass - try: - temp_list[13] += "Poll - Description: "+ str(y['poll']['extended']['descr'])+"," - except KeyError: - pass - try: - if y['poll']['options']: - z = '' - for x in y['poll']['options']: - try: - z = x['count'] - temp_list[13] += "Poll - Options - Count: "+ str(z)+"," - except (KeyError,IndexError) as e: - pass - try: - z = x['name'] - temp_list[13] += "Poll - Options - Name: "+ str(z)+"," - except (KeyError,IndexError) as e: - pass - try: - z = x['isLiked'] - temp_list[13] += "Poll - Options - Is Liked: "+ str(z)+"," - except (KeyError,IndexError) as e: - pass - except (KeyError,IndexError) as e: - pass - - #quote values - if "quote" in y: - try: - temp_list[13] += "Quote - Text: "+ str(y['quote']['text'])+"," - except KeyError: - pass - try: - temp_list[13] += "Quote - Name: "+ str(y['quote']['name'])+"," - except KeyError: - pass - try: - temp_list[13] += "Quote - Attachment Name: "+ str(y['quote']['attachmentName'])+"," - except KeyError: - pass - try: - temp_list[13] += "Quote - Attachment UID: "+ str(y['quote']['attachmentUID'])+"," - except KeyError: - pass - try: - temp_list[13] += "Quote - Attachment Preview Path: "+ str(y['quote']['attachmentPreviewPath'])+"," - except KeyError: - pass - try: - temp_list[13] += "Quote - Text Meta Info - Data: "+ y['quote']['textMetaInfo_v2'][0]['data']+"," - except (KeyError,IndexError) as e: - pass - - if temp_list[10] == 'Outgoing': - temp_list[0] = viber_settings['_myUserName'] - temp_list[1] = '' - temp_list[2] = viber_settings['_myPhoneNumber'] - - if row[15] is not None: - thumb = media_to_html(row[15], files_found, report_folder) - else: - thumb = '' - - row = tuple(temp_list) - data_list.append((row[6], row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[14], row[15], thumb, row[8], row[9], row[10], row[11], row[12], row[16], row[17], row[18],row[19], row[20], row[21], row[22], row[23], row[24], row[25], row[26], row[13])) - - - if usageentries > 0: - report = ArtifactHtmlReport('Viber - Chats') - report.start_artifact_report(report_folder, 'Viber - Chats') - report.add_script() - data_headers = ('Timestamp', 'Sender (Display Full Name)','Sender (Display Short Name)','Sender (Phone)','Chat Name','Chat Participant(s)','Chat Phone(s)', 'Message Creation Date - UTC','Message Change State Date - UTC','Message Content','Attachment Name', 'Attachment','Call Date - UTC','Call Type','State','Duration (Seconds)','System Type Description','Attachment Type','Attachment Size','Latitude','Longitude','Conversation Deleted','Message Deleted', 'Conversation Time Bomb Duration','Message Time Bomb Duration','Message Time Bomb Timestamp - UTC','Conversation Marked Favorite','Likes Count','Message Metadata Fragments') - report.write_artifact_data_table(data_headers, data_list, file_found, html_no_escape=['Attachment']) #html_escape=False - report.end_artifact_report() - - kmlactivity = 'Viber - Chats' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - tsvname = 'Viber - Chats' - tsv(report_folder, data_headers, data_list, tsvname) - - db.close() - else: - logfunc('No Viber data found.') - \ No newline at end of file diff --git a/scripts/artifacts/voiceRecordings.py b/scripts/artifacts/voiceRecordings.py deleted file mode 100644 index cfe286e6..00000000 --- a/scripts/artifacts/voiceRecordings.py +++ /dev/null @@ -1,65 +0,0 @@ -import plistlib -from datetime import datetime -import shutil -from os import listdir -from os.path import isfile, join, basename, dirname - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline - - -def unix_epoch_to_readable_date(unix_epoch_time): - unix_time = float(unix_epoch_time + 978307200) - readable_time = datetime.utcfromtimestamp(unix_time).strftime('%Y-%m-%d %H:%M:%S') - return readable_time - - -def get_voiceRecordings(files_found, report_folder, seeker): - if len(files_found) > 0: - data_list = [] - plist_files = [] - - for file_found in files_found: - if file_found.endswith('plist'): - plist_files.append(file_found) - elif file_found.endswith('m4a'): - m4a_filename = basename(file_found) - if ' ' in m4a_filename: - m4a_filename = m4a_filename.replace(' ', '_') - shutil.copyfile(file_found, join(report_folder, m4a_filename)) - - plist_files.sort() - m4a_files = [join(report_folder, file) for file in listdir(report_folder) if isfile(join(report_folder, file))] - m4a_files.sort() - - for plist_file, m4a_file in zip(plist_files, m4a_files): - with open(plist_file, "rb") as file: - pl = plistlib.load(file) - ct = unix_epoch_to_readable_date(pl['RCSavedRecordingCreationTime']) - - audio = ''' - - '''.format(m4a_file) - - data_list.append((ct, pl['RCSavedRecordingTitle'], pl['RCComposedAVURL'].split('//')[1], audio)) - - report = ArtifactHtmlReport('Voice Recordings') - report.start_artifact_report(report_folder, 'Voice Recordings') - report.add_script() - data_headers = ('Creation Date', 'Title', 'Path to File', 'Audio File') - report.write_artifact_data_table(data_headers, data_list, dirname(file_found), html_no_escape=['Audio File']) - report.end_artifact_report() - - tsvname = 'Voice Recordings' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Voice Recordings' - timeline(report_folder, tlactivity, data_list, data_headers) - - else: - logfunc('No Voice Recordings found') - - return diff --git a/scripts/artifacts/voiceTriggers.py b/scripts/artifacts/voiceTriggers.py deleted file mode 100644 index bfca8d5f..00000000 --- a/scripts/artifacts/voiceTriggers.py +++ /dev/null @@ -1,64 +0,0 @@ -import json -import datetime -import shutil -from os import listdir -from os.path import isfile, join, basename, dirname - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, timeline - - -def format_time(date_time_str): - date_time_obj = datetime.datetime.strptime(date_time_str, '%Y%m%d') - formatted = '{}-{}-{}'.format(date_time_obj.year, date_time_obj.month, date_time_obj.day) - return formatted - - -def get_voiceTriggers(files_found, report_folder, seeker): - info_files = [] - data_list = [] - if len(files_found) > 1: - for file_found in files_found: - if file_found.endswith('wav'): - shutil.copyfile(file_found, join(report_folder, basename(file_found))) - elif file_found.endswith('json') and 'meta_version.json' != basename(file_found): - info_files.append(file_found) - - info_files.sort() - wav_files = [join(report_folder, file) for file in listdir(report_folder) if isfile(join(report_folder, file))] - wav_files.sort() - - for info_file, wav_file in zip(info_files, wav_files): - if basename(info_file).split('.')[0] == basename(wav_file).split('.')[0]: - with open(info_file, "rb") as file: - fl = json.load(file) - if 'grainedDate' in fl: - creation_date = format_time(fl['grainedDate']) - else: - creation_date = '' - - audio = ''' - - '''.format(wav_file) - - data_list.append((creation_date, fl['productType'], fl['utteranceWav'], audio)) - - report = ArtifactHtmlReport('Voice Triggers') - report.start_artifact_report(report_folder, 'Voice Triggers') - report.add_script() - data_headers = ('Creation Date', 'Device', 'Path to File', 'Audio File') - report.write_artifact_data_table(data_headers, data_list, dirname(file_found), html_no_escape=['Audio File']) - report.end_artifact_report() - - tsvname = 'Voice Triggers' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Voice Triggers' - timeline(report_folder, tlactivity, data_list, data_headers) - else: - logfunc('No Voice Triggers found') - - return diff --git a/scripts/artifacts/walStrings.py b/scripts/artifacts/walStrings.py deleted file mode 100644 index e7c43ae9..00000000 --- a/scripts/artifacts/walStrings.py +++ /dev/null @@ -1,63 +0,0 @@ -import os -import re -import string - -from pathlib import Path -from html import escape - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, is_platform_windows - -control_chars = ''.join(map(chr, range(0,32))) + ''.join(map(chr, range(127,160))) -not_control_char_re = re.compile(f'[^{control_chars}]' + '{4,}') -# If we only want ascii, use 'ascii_chars_re' below -printable_chars_for_re = string.printable.replace('\\', '\\\\').replace('[', '\\[').replace(']', '\\]') -ascii_chars_re = re.compile(f'[{printable_chars_for_re}]' + '{4,}') - -def get_walStrings(files_found, report_folder, seeker): - x = 1 - data_list = [] - for file_found in files_found: - filesize = Path(file_found).stat().st_size - if filesize == 0: - continue - - journalName = os.path.basename(file_found) - outputpath = os.path.join(report_folder, str(x) + '_' + journalName + '.txt') # name of file in txt - - level2, level1 = (os.path.split(outputpath)) - level2 = (os.path.split(level2)[1]) - final = level2 + '/' + level1 - - unique_items = set() # For deduplication of strings found - with open(outputpath, 'w') as g: - with open(file_found, errors="ignore") as f: # Python 3.x - data = f.read() - #for match in not_control_char_re.finditer(data): # This gets all unicode chars, can include lot of garbage if you only care about English, will miss out other languages - for match in ascii_chars_re.finditer(data): # Matches ONLY Ascii (old behavior) , good if you only care about English - if match.group() not in unique_items: - g.write(match.group()) - g.write('\n') - unique_items.add(match.group()) - g.close() - - if unique_items: - out = (f'{journalName}') - data_list.append((out, file_found)) - else: - try: - os.remove(outputpath) # delete empty file - except OSError: - pass - x = x + 1 - - location ='' - description = 'ASCII strings extracted from SQLite journal and WAL files.' - report = ArtifactHtmlReport('Strings - SQLite Journal & WAL') - report.start_artifact_report(report_folder, 'Strings - SQLite Journal & WAL', description) - report.add_script() - data_headers = ('Report', 'Location') - report.write_artifact_data_table(data_headers, data_list, location, html_escape=False) - report.end_artifact_report() - - \ No newline at end of file diff --git a/scripts/artifacts/weatherAppLocations.py b/scripts/artifacts/weatherAppLocations.py deleted file mode 100644 index 0e6c6fa0..00000000 --- a/scripts/artifacts/weatherAppLocations.py +++ /dev/null @@ -1,50 +0,0 @@ -import plistlib -import time - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, kmlgen, timeline, is_platform_windows - - -def get_weatherAppLocations(files_found, report_folder, seeker): - data_list = [] - - for file_found in files_found: - file_found = str(file_found) - with open(file_found, "rb") as plist_file: - plist_content = plistlib.load(plist_file) - - for city in plist_content['Cities']: - update_time = city['UpateTime'] - update_time_formatted = update_time.strftime('%Y-%m-%d %H:%M:%S') - - data_list.append((update_time_formatted, 'Added from User', '', city['Lat'], - city['Lon'], city['Name'], city['Country'], city['SecondsFromGMT'])) - - local_weather = plist_content['LocalWeather'] - local_update_time = local_weather['UpateTime'] - local_update_time_formatted = local_update_time.strftime('%Y-%m-%d %H:%M:%S') - last_location_update = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(plist_content.get('LastLocationUpdateTime'))) - - data_list.append((local_update_time_formatted, 'Local', last_location_update, local_weather['Lat'], - local_weather['Lon'], local_weather['Name'], local_weather['Country'], local_weather['SecondsFromGMT'])) - - if len(data_list) > 0: - report = ArtifactHtmlReport('Weather App Locations') - report.start_artifact_report(report_folder, 'Weather App Locations') - report.add_script() - data_headers = ("Update Time", "Type", "Last Location Update", "Latitude", "Longitude", "City", "Country", "Seconds from GMT") - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Weather App Locations' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = 'Weather App Locations' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Weather App Locations' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - else: - logfunc('No data available for Weather App Locations') - \ No newline at end of file diff --git a/scripts/artifacts/webClips.py b/scripts/artifacts/webClips.py deleted file mode 100644 index a9df41db..00000000 --- a/scripts/artifacts/webClips.py +++ /dev/null @@ -1,72 +0,0 @@ -import os -import plistlib -import base64 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, tsv, is_platform_windows - - -def get_webClips(files_found, report_folder, seeker): - webclip_data = {} - data_list = [] - for path_val in files_found: - # Extract the unique identifier - pathstr = str(path_val).replace("\\", "/") - - unique_id = pathstr.split("/WebClips/")[1].split(".webclip/")[0] - if unique_id.endswith('.webclip'): - unique_id = unique_id[:-8] - if unique_id != "" and unique_id not in webclip_data: - webclip_data[unique_id] = { - "Info": "", - "Icon_path": "", - "Icon_data": "", - "Title": "", - "URL": "", - } - # Is this the path to the info.plist? - if "Info.plist" in pathstr: - webclip_data[unique_id]["Info"] = path_val - - # Is this the path to the icon? - if "icon.png" in pathstr: - webclip_data[unique_id]["Icon_path"] = path_val - - logfunc(f"Webclips found: {len(webclip_data)} ") - - for unique_id, data in webclip_data.items(): - # Info plist information - #logfunc(str(data)) - info_plist_raw = open(data["Info"], "rb") - info_plist = plistlib.load(info_plist_raw) - webclip_data[unique_id]["Title"] = info_plist["Title"] - webclip_data[unique_id]["URL"] = info_plist["URL"] - info_plist_raw.close() - - # Open and convert icon into b64 for serialisation in report - icon_data_raw = open(data["Icon_path"], "rb") - icon_data = base64.b64encode(icon_data_raw.read()).decode("utf-8") - webclip_data[unique_id]["Icon_data"] = icon_data - icon_data_raw.close() - - # Create the report - for unique_id, data in webclip_data.items(): - htmlstring = (f'
Data typeValue
ASCII" + str(plist2[i]) + "
ASCII" + str(plist2[i]) + "
Null" + str(plist2[i]) + "
ASCII" + str(plist2[i]) + "
NS.data") - h.write(str(secondplistint)) - h.write("
NS.data") - h.write(str(secondplistint)) - h.write("
') - htmlstring = htmlstring +('') - htmlstring = htmlstring +(f'') - htmlstring = htmlstring +(f'') - htmlstring = htmlstring +('') - htmlstring = htmlstring +('
UID:{unique_id}
Title: {data["Title"]}
URL: {data["URL"]}
') - data_list.append((htmlstring,)) - - - report = ArtifactHtmlReport(f'WebClips') - report.start_artifact_report(report_folder, f'WebClips') - report.add_script() - data_headers = ((f'WebClips',)) - report.write_artifact_data_table(data_headers, data_list, files_found[0], html_escape=False) - report.end_artifact_report() - - - - diff --git a/scripts/artifacts/whatsappContacts.py b/scripts/artifacts/whatsappContacts.py deleted file mode 100644 index d5fd4152..00000000 --- a/scripts/artifacts/whatsappContacts.py +++ /dev/null @@ -1,61 +0,0 @@ -import sqlite3 -import io -import json -import os -import shutil -import nska_deserialize as nd -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_whatsappContacts(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - break - data_list =[] - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - ZFULLNAME, - ZABOUTTEXT, - datetime(ZABOUTTIMESTAMP+978307200, 'UNIXEPOCH'), - ZPHONENUMBER, - ZPHONENUMBERLABEL, - ZWHATSAPPID, - ZIDENTIFIER - FROM ZWAADDRESSBOOKCONTACT - ''') - all_rows = cursor.fetchall() - usageentries = len(all_rows) - - if usageentries > 0: - for row in all_rows: - - data_list.append((row[0], row[1], row[2], row[3], row[4], row[5],row[6])) - - - - description = 'Whatsapp - Contacts' - report = ArtifactHtmlReport('Whatsapp - Contacts') - report.start_artifact_report(report_folder, 'Whatsapp - Contacts') - report.add_script() - data_headers = ( - 'Fullname', 'About Text', 'About Text Timestamp', 'Phone Number', 'Phone Number Label', 'Whatsapp ID', 'Identifier') - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - - tsvname = f'Whatsapp - Contacts' - tsv(report_folder, data_headers, data_list, tsvname) - - else: - logfunc('Whatsapp - Contacts data available') - - \ No newline at end of file diff --git a/scripts/artifacts/whatsappMessages.py b/scripts/artifacts/whatsappMessages.py deleted file mode 100644 index f853883f..00000000 --- a/scripts/artifacts/whatsappMessages.py +++ /dev/null @@ -1,117 +0,0 @@ -import sqlite3 -import io -import json -import os -import shutil -import nska_deserialize as nd -import scripts.artifacts.artGlobals - -from packaging import version -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, logdevinfo, timeline, kmlgen, tsv, is_platform_windows, open_sqlite_db_readonly - - -def get_whatsappMessages(files_found, report_folder, seeker): - - for file_found in files_found: - file_found = str(file_found) - - if file_found.endswith('.sqlite'): - break - data_list =[] - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - select - datetime(ZMESSAGEDATE+978307200, 'UNIXEPOCH'), - ZISFROMME, - ZPARTNERNAME, - ZFROMJID, - ZTOJID, - ZWAMESSAGE.ZMEDIAITEM, - ZTEXT, - ZSTARRED, - ZMESSAGETYPE, - ZLONGITUDE, - ZLATITUDE, - ZMEDIALOCALPATH, - ZXMPPTHUMBPATH - FROM ZWAMESSAGE - left JOIN ZWAMEDIAITEM - on ZWAMESSAGE.Z_PK = ZWAMEDIAITEM.ZMESSAGE - left JOIN ZWACHATSESSION - on ZWACHATSESSION.Z_PK = ZWAMESSAGE.ZCHATSESSION - ''') - all_rows = cursor.fetchall() - usageentries = len(all_rows) - - if usageentries > 0: - for row in all_rows: - - if row[1] == 1: - sender = 'Local User' - receiver = row[2] - else: - sender = row[2] - receiver = 'Local User' - - if row[8] == 5: - lon = row[9] - lat = row[10] - else: - lat = '' - lon = '' - - attfile = row[11] - attachment = row[12] - localpath = row[11] - - - if attachment is not None: - for match in files_found: - if attachment in match: - shutil.copy2(match, report_folder) - data_file_name = os.path.basename(match) - thumb = f'' - else: - thumb = '' - - - if attfile is not None: - for matchf in files_found: - if attfile in matchf: - shutil.copy2(matchf, report_folder) - data_file_namef = os.path.basename(matchf) - attfile = f'' - else: - attfile = '' - - data_list.append((row[0], sender, row[3], receiver, row[4], row[6], attfile, thumb, localpath,row[7], lat, lon,)) - - - - description = 'Whatsapp - Messages' - report = ArtifactHtmlReport('Whatsapp - Messages') - report.start_artifact_report(report_folder, 'Whatsapp - Messages') - report.add_script() - data_headers = ( - 'Timestamp', 'Sender Name', 'From ID', 'Receiver', 'To ID', 'Message', - 'Attachment File', 'Thumb','Attachment Local Path','Starred?', 'Latitude', 'Longitude',) # Don't remove the comma, that is required to make this a tuple as there is only 1 element - - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape=False) - report.end_artifact_report() - - - tsvname = f'Whatsapp - Messages' - tsv(report_folder, data_headers, data_list, tsvname) - - tlactivity = f'Whatsapp - Messages' - timeline(report_folder, tlactivity, data_list, data_headers) - - kmlactivity = 'Whatsapp - Messages' - kmlgen(report_folder, kmlactivity, data_list, data_headers) - - else: - logfunc('Whatsapp - Messages data available') - - \ No newline at end of file diff --git a/scripts/artifacts/wiLoc.py b/scripts/artifacts/wiLoc.py deleted file mode 100644 index a136fe02..00000000 --- a/scripts/artifacts/wiLoc.py +++ /dev/null @@ -1,53 +0,0 @@ -import glob -import os -import pathlib -import plistlib -import sqlite3 - -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, tsv, is_platform_windows, open_sqlite_db_readonly - -def get_celw(files_found, report_folder, seeker): - file_found = str(files_found[0]) - db = open_sqlite_db_readonly(file_found) - cursor = db.cursor() - cursor.execute(''' - SELECT - ZADDRESS AS "ADDRESS", - ZANSWERED AS "WAS ANSWERED", - ZCALLTYPE AS "CALL TYPE", - ZORIGINATED AS "ORIGINATED", - ZDURATION AS "DURATION (IN SECONDS)", - ZISO_COUNTRY_CODE as "ISO COUNTY CODE", - ZLOCATION AS "LOCATION", - ZSERVICE_PROVIDER AS "SERVICE PROVIDER", - DATETIME(ZDATE+978307200,'UNIXEPOCH') AS "TIMESTAMP" - FROM ZCALLRECORD - ''') - - all_rows = cursor.fetchall() - usageentries = len(all_rows) - if usageentries > 0: - data_list = [] - for row in all_rows: - an = str(row[0]) - an = an.replace("b'", "") - an = an.replace("'", "") - data_list.append((row[8],an,row[1],row[2],row[3],row[4],row[5],row[6],row[7])) - - report = ArtifactHtmlReport('Call Logs') - report.start_artifact_report(report_folder, 'Call Logs') - report.add_script() - data_headers = ('Timestamp','Address','Was Answered','Call Type','Originated','Duration in Secs','ISO County Code','Location','Service Provider' ) - report.write_artifact_data_table(data_headers, data_list, file_found) - report.end_artifact_report() - - tsvname = 'Call Logs' - tsv(report_folder, data_headers, data_list, tsvname) - else: - logfunc('No Call History data available') - - db.close() - return - - diff --git a/scripts/html_parts.py b/scripts/html_parts.py index 73509b91..95706f5e 100644 --- a/scripts/html_parts.py +++ b/scripts/html_parts.py @@ -206,13 +206,13 @@
-
Thank you for using iLEAPP
+
Thank you for using iLTriage

Support open source and report any bugs!

- Project Home -

iLEAPP Team

+ Project Home +

iLTriage Team

@@ -226,7 +226,7 @@ credits_block = \ """
-

iLEAPP contributors

+

iLTriage contributors

    {}
diff --git a/scripts/ilap_artifacts.py b/scripts/ilap_artifacts.py index cb12b28c..20265c44 100644 --- a/scripts/ilap_artifacts.py +++ b/scripts/ilap_artifacts.py @@ -6,104 +6,10 @@ import traceback from time import process_time, gmtime, strftime -from scripts.artifacts.accs import get_accs -from scripts.artifacts.addressBook import get_addressBook -from scripts.artifacts.alarms import get_alarms -from scripts.artifacts.appConduit import get_appConduit -from scripts.artifacts.appGrouplisting import get_appGrouplisting -from scripts.artifacts.appItunesmeta import get_appItunesmeta -from scripts.artifacts.appSnapshots import get_applicationSnapshots -from scripts.artifacts.appleMapsApplication import get_appleMapsApplication -from scripts.artifacts.appleMapsGroup import get_appleMapsGroup -from scripts.artifacts.appleMapsSearchHistory import get_appleMapsSearchHistory -from scripts.artifacts.applePodcasts import get_applePodcasts -from scripts.artifacts.appleWifiPlist import get_appleWifiPlist -from scripts.artifacts.appleWalletCards import get_appleWalletCards -from scripts.artifacts.appleWalletPasses import get_appleWalletPasses -from scripts.artifacts.appleWalletTransactions import get_appleWalletTransactions -from scripts.artifacts.applicationstate import get_applicationstate -from scripts.artifacts.airtags import get_airtags -from scripts.artifacts.bluetooth import get_bluetooth -from scripts.artifacts.cacheRoutesGmap import get_cacheRoutesGmap -from scripts.artifacts.calendarAll import get_calendarAll -from scripts.artifacts.callHistory import get_callHistory -from scripts.artifacts.cashApp import get_cashApp -from scripts.artifacts.celWireless import get_celWireless -from scripts.artifacts.cloudkitSharing import get_cloudkitSharing -from scripts.artifacts.conDev import get_conDev -from scripts.artifacts.confaccts import get_confaccts -from scripts.artifacts.deviceActivator import get_deviceActivator -from scripts.artifacts.dhcphp import get_dhcphp -from scripts.artifacts.dhcpl import get_dhcpl -from scripts.artifacts.discordAcct import get_discordAcct -from scripts.artifacts.discordJson import get_discordJson -from scripts.artifacts.discordManifest import get_discordManifest -from scripts.artifacts.FacebookMessenger import get_FacebookMessenger -from scripts.artifacts.filesAppsclient import get_filesAppsclient -from scripts.artifacts.filesAppsdb import get_filesAppsdb -from scripts.artifacts.filesAppsm import get_filesAppsm -from scripts.artifacts.geodApplications import get_geodApplications -from scripts.artifacts.geodMapTiles import get_geodMapTiles -from scripts.artifacts.geodPDPlaceCache import get_geodPDPlaceCache -from scripts.artifacts.googleDuo import get_googleDuo -from scripts.artifacts.icloudMeta import get_icloudMeta -from scripts.artifacts.icloudPhotoMeta import get_icloudPhotoMeta -from scripts.artifacts.quickLook import get_quickLook -from scripts.artifacts.iCloudWifi import get_iCloudWifi -from scripts.artifacts.icloudSharedalbums import get_icloudSharedalbums -from scripts.artifacts.iconsScreen import get_iconsScreen -from scripts.artifacts.imoHD_Chat import get_imoHD_Chat -from scripts.artifacts.instagramThreads import get_instagramThreads -from scripts.artifacts.interactionCcontacts import get_interactionCcontacts -from scripts.artifacts.keyboardAppUsage import get_keyboardAppUsage -from scripts.artifacts.keyboardLexicon import get_keyboardLexicon -from scripts.artifacts.kikMessages import get_kikMessages -from scripts.artifacts.kikBplistmeta import get_kikBplistmeta -from scripts.artifacts.kikPendingUploads import get_kikPendingUploads -from scripts.artifacts.kikUsersgroups import get_kikUsersgroups -from scripts.artifacts.locServicesconfig import get_locServicesconfig + from scripts.artifacts.lastBuild import get_lastBuild, get_iTunesBackupInfo -from scripts.artifacts.mailprotect import get_mailprotect -from scripts.artifacts.mediaLibrary import get_mediaLibrary -from scripts.artifacts.medicalID import get_medicalID -from scripts.artifacts.mobileActivationLogs import get_mobileActivationLogs -from scripts.artifacts.mobileBackup import get_mobileBackup -from scripts.artifacts.mobileContainerManager import get_mobileContainerManager -from scripts.artifacts.mobileInstall import get_mobileInstall -from scripts.artifacts.notes import get_notes -from scripts.artifacts.notificationsXI import get_notificationsXI -from scripts.artifacts.notificationsXII import get_notificationsXII -from scripts.artifacts.ooklaSpeedtestData import get_ooklaSpeedtestData -from scripts.artifacts.photosMetadata import get_photosMetadata -from scripts.artifacts.protonMail import get_protonMail -from scripts.artifacts.recentApphistory import get_recentApphistory -from scripts.artifacts.reminders import get_reminders -from scripts.artifacts.restoreLog import get_restoreLog -from scripts.artifacts.queryPredictions import get_queryPredictions -from scripts.artifacts.safariBookmarks import get_safariBookmarks -from scripts.artifacts.safariFavicons import get_safariFavicons -from scripts.artifacts.safariRecentWebSearches import get_safariRecentWebSearches -from scripts.artifacts.safariTabs import get_safariTabs -from scripts.artifacts.safariWebsearch import get_safariWebsearch -from scripts.artifacts.slack import get_slack -from scripts.artifacts.tcc import get_tcc -from scripts.artifacts.teams import get_teams -from scripts.artifacts.teamsSegment import get_teamsSegment -from scripts.artifacts.textinputTyping import get_textinputTyping -from scripts.artifacts.tikTok import get_tikTok -from scripts.artifacts.tileApp import get_tileApp -from scripts.artifacts.tileAppDb import get_tileAppDb -from scripts.artifacts.tileAppDisc import get_tileAppDisc -from scripts.artifacts.tileAppNetDb import get_tileAppNetDb -from scripts.artifacts.walStrings import get_walStrings -from scripts.artifacts.webClips import get_webClips -from scripts.artifacts.weatherAppLocations import get_weatherAppLocations -from scripts.artifacts.whatsappContacts import get_whatsappContacts -from scripts.artifacts.whatsappMessages import get_whatsappMessages -from scripts.artifacts.venmo import get_venmo -from scripts.artifacts.viber import get_viber -from scripts.artifacts.voiceTriggers import get_voiceTriggers -from scripts.artifacts.voiceRecordings import get_voiceRecordings + +from scripts.artifacts.routineD import get_routineD from scripts.ilapfuncs import * @@ -116,105 +22,7 @@ tosearch = {'lastBuild': ('IOS Build', '*LastBuildInfo.plist'), - 'accs': ('Accounts', '**/Accounts3.sqlite'), - 'addressBook': ('Address Book', '**/AddressBook.sqlitedb'), - 'alarms': ('Alarms', '*private/var/mobile/Library/Preferences/com.apple.mobiletimerd.plist'), - 'appConduit': ('App Conduit', '**/AppConduit.log.*'), - 'appGrouplisting': ('Installed Apps', ('*/Containers/Shared/AppGroup/*/.com.apple.mobile_container_manager.metadata.plist', '**/PluginKitPlugin/*.metadata.plist')), - 'appItunesmeta': ('Installed Apps', ('**/iTunesMetadata.plist', '**/BundleMetadata.plist')), - 'appleMapsApplication': ('Locations', '**/Data/Application/*/Library/Preferences/com.apple.Maps.plist'), - 'appleMapsGroup': ('Locations', '**/Shared/AppGroup/*/Library/Preferences/group.com.apple.Maps.plist'), - 'appleMapsSearchHistory': ('Locations', '*private/var/mobile/Containers/Data/Application/*/Library/Maps/GeoHistory.mapsdata'), - 'applePodcasts': ('Apple Podcasts', '**/MTLibrary.sqlite*'), - 'appleWalletCards': ('Apple Wallet', '*/private/var/mobile/Containers/Data/Application/*/Library/Caches/com.apple.Passbook/Cache.db*'), - 'appleWalletPasses': ('Apple Wallet', ('**/nanopasses.sqlite3*', '**/Cards/*.pkpass/pass.json')), - 'appleWalletTransactions': ('Apple Wallet', '**/passes23.sqlite'), - 'appleWifiPlist': ('Wifi Connections', ('**/com.apple.wifi.plist', '**/com.apple.wifi-networks.plist.backup', '**/com.apple.wifi.known-networks.plist', '**/com.apple.wifi-private-mac-networks.plist')), - 'applicationSnapshots': ('Installed Apps', ('**/Library/Caches/Snapshots/*', '**/SplashBoard/Snapshots/*')), - 'applicationstate': ('Installed Apps', '**/applicationState.db'), - 'airtags': ('Airtags', '*/Caches/com.apple.findmy.fmipcore/Items.data'), - 'bluetooth': ('Bluetooth', '**/com.apple.MobileBluetooth.*'), - 'cacheRoutesGmap': ('Locations', '**/Library/Application Support/CachedRoutes/*.plist'), - 'calendarAll': ('Calendar', '**/Calendar.sqlitedb'), - 'callHistory': ('Call History', '**/CallHistory.storedata*'), - 'cashApp': ('Cash App', '**private/var/mobile/Containers/Shared/AppGroup/*/CCEntitySync-api.squareup.com.sqlite*'), - 'celWireless': ('Cellular Wireless', '*wireless/Library/Preferences/com.apple.*'), - 'cloudkitSharing': ('Cloudkit', '*NoteStore.sqlite*'), - 'conDev': ('Connected to', '**/iTunes_Control/iTunes/iTunesPrefs'), - 'confaccts': ('Accounts', '**/com.apple.accounts.exists.plist'), - 'deviceActivator': ('IOS Build', '*private/var/mobile/Library/Logs/mobileactivationd/ucrt_oob_request.txt'), - 'dhcphp': ('DHCP', '**/private/var/db/dhcpd_leases*'), - 'dhcpl': ('DHCP', '**/private/var/db/dhcpclient/leases/en*'), - 'discordAcct': ('Discord', '*/var/mobile/Containers/Data/Application/*/Documents/mmkv/mmkv.default'), - 'discordJson': ('Discord', '*/com.hammerandchisel.discord/fsCachedData/*'), - 'discordManifest': ('Discord', '*/private/var/mobile/Containers/Data/Application/*/Documents/RCTAsyncLocalStorage_V1/manifest.json'), - 'FacebookMessenger': ('Facebook Messenger', '**/lightspeed-*.db*'), - 'filesAppsclient': ('Files App', '*private/var/mobile/Library/Application Support/CloudDocs/session/db/client.db*'), - 'filesAppsdb': ('Files App', '*private/var/mobile/Library/Application Support/CloudDocs/session/db/server.db*'), - 'filesAppsm': ('Files App', '*private/var/mobile/Containers/Shared/AppGroup/*/smartfolders.db*'), - 'geodApplications': ('Geolocation', '**/AP.db'), - 'geodMapTiles': ('Geolocation', '**/MapTiles.sqlitedb'), - 'geodPDPlaceCache': ('Geolocation', '**/PDPlaceCache.db'), - 'googleDuo': ('Google Duo', ('*/Application Support/DataStore*','*/Application Support/ClipsCache/*.png')), - 'icloudMeta': ('iCloud Returns', '*/iclouddrive/Metadata.txt'), - 'icloudPhotoMeta': ('iCloud Returns', '*/cloudphotolibrary/Metadata.txt'), - 'icloudSharedalbums': ('iCloud Shared Albums', '*/private/var/mobile/Media/PhotoData/PhotoCloudSharingData/*'), - 'iCloudWifi': ('Wifi Connections', '**/com.apple.wifid.plist'), - 'iconsScreen': ('iOS Screens', '**/SpringBoard/IconState.plist'), - 'imoHD_Chat': ('IMO HD Chat', ('**/IMODb2.sqlite*','private/var/mobile/Containers/Data/Application/*/Library/Caches/videos/*.webp')), - 'instagramThreads':('Instagram', '*/mobile/Containers/Data/Application/*/Library/Application Support/DirectSQLiteDatabase/*.db*'), - 'interactionCcontacts': ('InteractionC', '**/interactionC.db'), - 'keyboardAppUsage': ('Keyboard', '*/private/var/mobile/Library/Keyboard/app_usage_database.plist'), - 'keyboardLexicon': ('Keyboard', '*/private/var/mobile/Library/Keyboard/*-dynamic.lm/dynamic-lexicon.dat'), - 'kikMessages': ('Kik', ('**/kik.sqlite*','*/mobile/Containers/Shared/AppGroup/*/cores/private/*/content_manager/data_cache/*')), - 'kikBplistmeta': ('Kik', '*/mobile/Containers/Shared/AppGroup/*/cores/private/*/attachments/*'), - 'kikPendingUploads': ('Kik', ('*/mobile/Containers/Shared/AppGroup/*/cores/private/*/chunked_upload_storage/pending_uploads','*/mobile/Containers/Shared/AppGroup/*/cores/private/*/chunked_upload_storage/data_cache/*')), - 'kikUsersgroups':('Kik', ('*/kik.sqlite*')), - 'locServicesconfig': ('Location Services Configurations', ('*/Library/Preferences/com.apple.locationd.plist','*/Library/Caches/locationd/clients.plist', '*/Library/Preferences/com.apple.routined.plist')), - 'mailprotect': ('iOS Mail', '**/private/var/mobile/Library/Mail/* Index*'), - 'mediaLibrary': ('Media Library', '**/Medialibrary.sqlitedb'), - 'medicalID': ('Medical ID', '*/private/var/mobile/Library/MedicalID/MedicalIDData.archive'), - 'mobileActivationLogs': ('Mobile Activation Logs', '**/mobileactivationd.log*'), - 'mobileBackup': ('Mobile Backup', '*/Preferences/com.apple.MobileBackup.plist'), - 'mobileContainerManager': ('Mobile Container Manager', '**/containermanagerd.log.*'), - 'mobileInstall': ('Mobile Installation Logs', '**/mobile_installation.log.*'), - 'notes': ('Notes', '*/NoteStore.sqlite*'), - 'notificationsXI': ('Notifications', '*PushStore*'), - 'notificationsXII': ('Notifications', '*private/var/mobile/Library/UserNotifications*'), - 'ooklaSpeedtestData': ('Applications', '**/speedtest.sqlite*'), - 'photosMetadata': ('Photos', '**/Photos.sqlite'), - 'protonMail': ('Proton Mail', ('*/group.ch.protonmail.protonmail.plist','*/ProtonMail.sqlite*','*/Containers/Data/Application/*/tmp/*')), - 'queryPredictions': ('SMS & iMessage', '**/query_predictions.db'), - 'quickLook': ('iCloud Quick Look', '*/Quick Look/cloudthumbnails.db*'), - 'recentApphistory':('CarPlay', '*/com.apple.CarPlayApp.plist'), - 'restoreLog':('Mobile Software Update', '**/private/var/mobile/MobileSoftwareUpdate/restore.log'), - 'reminders': ('Reminders', '**/Reminders/Container_v1/Stores/*.sqlite*'), - 'safariBookmarks': ('Safari Browser', '**/Safari/Bookmarks.db'), - 'safariRecentWebSearches': ('Safari Browser', '**/Library/Preferences/com.apple.mobilesafari.plist'), - 'safariTabs': ('Safari Browser', '**/Safari/BrowserState.db'), - 'safariWebsearch': ('Safari Browser', '**/Safari/History.db'), - 'safariFavicons': ('Safari Browser', '*/Containers/Data/Application/*/Library/Image Cache/Favicons/Favicons.db*'), - 'slack': ('Slack', '*/var/mobile/Containers/Data/Application/*/Library/Application Support/Slack/*/Database/main_db*'), - 'tcc': ('App Permissions', '*TCC.db*'), - 'teams': ('Microsoft Teams', ('*/var/mobile/Containers/Shared/AppGroup/*/SkypeSpacesDogfood/*/Skype*.sqlite*','*/var/mobile/Containers/Shared/AppGroup/*/SkypeSpacesDogfood/Downloads/*/Images/*')), - 'textinputTyping': ('Text Input Messages', '*/DES/Records/com.apple.TextInput.TypingDESPlugin/*.desdata'), - 'teamsSegment': ('Microsoft Teams - Logs', '*/var/mobile/Containers/Data/Application/*/Library/DriveIQ/segments/current/*.*'), - 'tikTok': ('TikTok', ('*/Application/*/Library/Application Support/ChatFiles/*/db.sqlite*', '*AwemeIM.db*')), - 'tileApp': ('Locations', '*private/var/mobile/Containers/Data/Application/*/Library/log/com.thetileapp.tile*'), - 'tileAppDb': ('Locations', '*private/var/mobile/Containers/Shared/AppGroup/*/com.thetileapp.tile-TileNetworkDB.sqlite*'), - 'tileAppDisc': ('Accounts','*/private/var/mobile/Containers/Shared/AppGroup/*/com.thetileapp.tile-DiscoveredTileDB.sqlite*'), - 'tileAppNetDb': ('Accounts', '*/private/var/mobile/Containers/Shared/AppGroup/*/com.thetileapp.tile-TileNetworkDB.sqlite*'), - 'voiceRecordings': ('Voice-Recordings', ('**/Recordings/*.composition/manifest.plist', '**/Recordings/*.m4a')), - 'voiceTriggers': ('Voice-Triggers', ('**/td/audio/*.json', '**/td/audio/*.wav')), - 'walStrings': ('SQLite Journaling', ('**/*-wal', '**/*-journal')), - 'whatsappMessages': ('Whatsapp', ('*/var/mobile/Containers/Shared/AppGroup/*/ChatStorage.sqlite*','*/var/mobile/Containers/Shared/AppGroup/*/Message/Media/*/*/*/*.*')), - 'whatsappContacts': ('Whatsapp', ('*/var/mobile/Containers/Shared/AppGroup/*/ContactsV2.sqlite*')), - 'weatherAppLocations': ('Locations', '*/private/var/mobile/Containers/Shared/AppGroup/*/Library/Preferences/group.com.apple.weather.plist'), - 'webClips': ('iOS Screens', '*WebClips/*.webclip/*'), - 'venmo':('Venmo', ('*PrivateFeed', '*PublicFeed', '*FriendsFeed')), - 'viber' : ('Viber', ('**/com.viber/settings/Settings.data','**/com.viber/database/Contacts.data','**/Containers/Data/Application/*/Documents/Attachments/*.*','**/com.viber/ViberIcons/*.*')), - # 'appUpdates':('App Updates', '**/AppUpdates.sqlitedb'), - # 'systemVersion':('Device Info', '**/SystemVersion.plist'), + 'routineD': ('Locations', ('*/var/mobile/Library/Caches/com.apple.routined/Cache.sqlite', '*/var/mobile/Library/Caches/com.apple.routined/Local.sqlite','*/var/mobile/Library/Caches/com.apple.routined/Cloud.sqlite')), } ''' diff --git a/scripts/report.py b/scripts/report.py index e38688c8..b832e0ad 100644 --- a/scripts/report.py +++ b/scripts/report.py @@ -440,14 +440,14 @@ def create_index_html(reportfolderbase, time_in_secs, time_HMS, extraction_type, # WRITE INDEX.HTML LAST filename = 'index.html' - page_title = 'iLEAPP Report' - body_heading = 'iOS Logs Events And Protobuf Parser' - body_description = 'iLEAPP is an open source project that aims to parse every known iOS artifact for the purpose of forensic analysis.' + page_title = 'iLTriage Report' + body_heading = 'iLTriage' + body_description = 'iOS Location Triage Tool.' active_nav_list_data = mark_item_active(nav_list_data, filename) + nav_bar_script f = open(os.path.join(reportfolderbase, filename), 'w', encoding='utf8') f.write(page_header.format(page_title)) - f.write(body_start.format(f"iLEAPP {aleapp_version}")) + f.write(body_start.format(f"iLTriage {aleapp_version}")) f.write(body_sidebar_setup + active_nav_list_data + body_sidebar_trailer) f.write(body_main_header + body_main_data_title.format(body_heading, body_description)) f.write(content) diff --git a/scripts/version_info.py b/scripts/version_info.py index a456659d..1fc874f0 100644 --- a/scripts/version_info.py +++ b/scripts/version_info.py @@ -1,4 +1,4 @@ -aleapp_version = '1.17.0' +aleapp_version = '1.0' # Contributors List # Format = [ Name, Blog-url, Twitter-handle, Github-url] @@ -6,31 +6,5 @@ aleapp_contributors = [ ['Alexis Brignoni', 'https://abrignoni.com', '@AlexisBrignoni', 'https://github.com/abrignoni'], ['Yogesh Khatri', 'https://swiftforensics.com', '@SwiftForensics', 'https://github.com/ydkhatri'], - ['Agam Dua', 'https://loopback.dev', '@loopbackdev', 'https://github.com/agamdua'], - ['Heather Mahalik', 'https://smarterforensics.com', '@HeatherMahalik', ''], - ['Jessica Hyde', 'https://twitter.com/B1N2H3X', '@B1N2H3X', ''], - ['Phill Moore', 'https://thinkdfir.com', '@phillmoore', 'https://github.com/randomaccess3'], - ['Mattia Epifani', 'https://blog.digital-forensics.it', '@mattiaep', ''], - ['Mike Williamson', 'https://forensicmike1.com', '@forensicmike1', 'https://github.com/forensicmike'], - ['Geraldine Blay', 'https://gforce4n6.blogspot.com', '@i_am_the_gia', ''], - ['Christopher Vance', 'https://blog.d204n6.com', '@cScottVance', ''], - ['Brooke Gottlieb', '', '@xbrookego', ''], - ['Jack Farley', 'http://farleyforensics.com', '@JackFarley248', ''], - ['Shafik Punja', '', '@qubytelogic', ''], - ['Cheeky4N6Monkey', 'https://cheeky4n6monkey.blogspot.com', '@Cheeky4n6Monkey', 'https://github.com/cheeky4n6monkey'], - ['Edward Greybeard', '', '', 'https://github.com/edward-greybeard'], - ['Douglas Kein', '', '@DouglasKein', ''], - ['Claudia Meda', '', '@KlodiaMaida', 'https://github.com/KlodiaMaida'], - ['Silvia Spallarossa', '', '@SilviaSpallaro1', 'https://github.com/spatimbs'], - ['Francesca Maestri', '', '@franc3sca_m', 'https://github.com/francyM'], - ['Christopher Vance', 'https://blog.d204n6.com/', '@cScottVance', 'https://github.com/cScottVance'], - ['Jesse Spangenberger', 'https://cyberfenixtech.blogspot.com/', '@AzuleOnyx', 'https://github.com/flamusdiu'], - ['Jon Baumann', 'https://ciofecaforensics.com/', '@CiofecaForensic', 'https://github.com/threeplanetssoftware'], - ['Scott Koenig', '', '@Scott_Kjr', ''], - ['Kevin Pagano', 'https://stark4n6.com/', '@KevinPagano3', 'https://github.com/stark4n6'], - ['Ed Michael', '', '@EdXlg123', 'https://github.com/edmichael'], - ['Anna-Mariya Mateyna', '', '@any333_snickers', 'https://github.com/any333'], - ['Tommy Harris', '', '@tobraha', 'https://github.com/tobraha'], - ['Troy Schnack', '', '@TroySchnack', ''], - ['Bo Amos', '', '@Bo_Knows_65', ''] + ['William Weathersby', '', '', 'https://github.com/22WEAT4N6'], ]