Rotten to the Core? Nah, iOS14 is Mostly Sweet

By Heather Mahalik

This blog is a cursory glance of iOS14, which was officially released this week. To keep with my previous trends, I focus on basic artifacts that impact almost every investigation and then dive in and take a bite from the apple. Think of this blog as the bobbing part. 😊 For this blog, I tested the tools that I have available to me personally. If you think something is missing – share it. If you are a vendor and think something is missing – share it with me and I will try it for myself. At this point in time, an encrypted iTunes backup seemed to be the most stable option. I know that vendors are releasing updates to support iOS14 shortly, so be patient. If you DO NOT encrypt the backup, you will NOT extract Calls, Apple Maps (some databases extracted but are empty), Safari, Health and probably a lot more!

Apple didn’t go of the beaten path to much for the primary artifacts. There are some strange things I noted and those will be shared. Since iOS13, best practices are to encrypt your backups! If you do not, you will not get all the databases needed for basic examinations.

For this blog, I acquired many ways to compare the differences. The ones in bold were the best acquisition.

Mac Acquisition Tests:

  • Backup on a Mac using Finder – Encrypted
  • Backup on a Mac using Finder – No encryption set
  • Backup on a Mac using Finder – Encryption set but DID NOT save the password to the keychain

The issue I found when backing up to a Mac and saving the encryption passcode to the keychain is that the Manifest.plist does not show the encryption flag and the tools do not request the passcode for parsing.

Manifest.plist comparison

Thus, you don’t get much of anything! I loaded all of these extractions into Cellebrite Physical Analyzer and Magnet AXIOM to verify and the keychain taking the passcode really limits us examiners so pay attention when using a Mac to create a backup and DO NOT let that box stay checked or your examination opportunities will be limited.

Backing up using a Mac

Windows Acquisition Tests:

I first attempted to use a previous version of iTunes and it didn’t even see my device running iOS14. I updated and all was good from that point forward.

  • Backup with iTunes – Encrypted
  • Backup with iTunes – No encryption set

There weren’t any oddities here other than the fact that as soon as I moved my backup from the MobileSync directory, iTunes claimed it was never backed up to this PC.

iTunes backup

And a backup a few mins later.

iTunes view after backup was moved from the MobileSync directory

Keep in mind, I did about 10 backups of this device because I kept adding data and then pulling it. It makes sense if you think about it, but I know that the device stores this information, so I was surprised to see iTunes simply relying on the backup directory for this information. Bottom line do not trust what iTunes states regarding backups on the summary screen because the truth lies within the iOS device.

For this test, I created new Contacts, placed Calls (both FaceTime and regular), texted (used the new “reply to a message” feature, took photos, searched for directions (and even had to do extra drives to get really test Maps), created a note, and browsed using Safari. These are the key items that everyone should examine for most cases, so I tend to start there. My colleagues and I are going to dive into the harder artifacts (KnowledgeC, locations, Health, etc.) and will do a separate blog on that.

The common artifacts:

Contacts: var/mobile/Library/AddressBook/AddressBook.sqlitedb – parsed by commercial tools

Calls: var/mobile/Library/CallHistoryDB/CallHistory.storedata – – parsed by commercial tools

PA Parsed Call Logs
PA Call logs with Source File

SMS: var/mobile/Library/SMS/sms.db – mostly parsed by commercial tools. See below for more details.

Safari: var/mobile/Library/Safari/History.db – mostly parsed by commercial tools. Note: Make sure your tool parses history, Google searches and Tab history.

AXIOM Tabbed Sessions
PA Safari History
PA Safari History – Source

Photos: var/mobile/Media/DCIM/100APPLE/ – parsed by commercial tools – However, there is a new table. Take a look below.

PA Photos

The table ZGENERICASSET that we have relied upon for so long is now ZASSET. Thanks to Jared Barnhart for finding this first. 🙂 And thanks to Scott Koenig for this query to parse it all. https://drive.google.com/drive/folders/1v6T6OqD8eyL1xwHXDMePaXxEZ3IZssp2

Notes: var/mobile/Containers/Shared/AppGroup/group.com.apple.notes/NoteStore.sqlite – parsed by commercial tools

**NEW File and Path***

Maps: var/mobile/Containers/Shared/AppGroup/group.com.apple.Maps/Maps/MapsSync_0.0.1

var/mobile/Containers/Shared/AppGroup/group.com.apple.Maps/Maps/MapsSync_0.0.1_deviceLocalCache.db

Apple Maps is the biggest change and to be honest, I thought I lost them again. If you aren’t sure what I am referring to, please read my previous blogs on Apple Maps. I have spent countless hours trying to find locations and you know what’s sad – I don’t even like Apple Maps. I prefer Waze. However, as a researcher, I must test all things. Let’s take a historical look at Apple Maps.

History. mapsdata – was the primary storage file for Maps until iOS 8

GeoHistory.mapsdata – the primary storage file for Maps from iOS 8 – iOS 11(ish). Went to cloud storage for iOS12 and then came back and stored here again for iOS13 – again refer to my previous blogs –How the Grinch stole Apple Maps artifacts… or did he just hide them? and First the Grinch and now the Easter Bunny! Where is Apple Maps hiding?

MapsSync_0.0.1 – the new file on the block – this is the primary file storing iOS 14 Maps data.

MapsSync_0.0.1 seems to only keep the last 15 history items. This is about 3-5 directions/lookups/searches based upon my testing. I dumped my device several times to confirm this. Let’s look.

Here is how it looked when I first extracted the data.

Apple Maps Data – DB Browser for SQLite

And just two Apple Maps searches later, it looked like this.

Apple Maps Data – DB Browser for SQLite

The bad news is that none of the tools I tested parse this file. The good news? Here is a query for you. Use your tool of choice to parse it. Keep in mind the “Time Created” below will reflect the time The device was updated to iOS14. Thus, this is NOT when that search occurred. To get that information, you need to examine GeoHistory.Mapsdata – the protobuf that stores this historical information.

SELECT
ZHISTORYITEM.z_pk AS "Item Number",
CASE
when ZHISTORYITEM.z_ent = 14 then "coordinates of search"
when ZHISTORYITEM.z_ent = 16 then "location search"
when ZHISTORYITEM.z_ent = 12 then "navigation journey"
end AS "Type",
datetime(ZHISTORYITEM.ZCREATETIME+978307200,'UNIXEPOCH','localtime') AS "Time Created",
datetime(ZHISTORYITEM.ZMODIFICATIONTIME+978307200,'UNIXEPOCH','localtime') AS "Time Modified",
ZHISTORYITEM.ZQUERY AS "Location Search",
ZHISTORYITEM.ZLOCATIONDISPLAY AS "Location City",
ZHISTORYITEM.ZLATITUDE AS "Latitude",
ZHISTORYITEM.ZLONGITUDE AS "Longitude",
ZHISTORYITEM.ZROUTEREQUESTSTORAGE AS "Journey BLOB",
ZMIXINMAPITEM.ZMAPITEMSTORAGE as "Map Item Storage BLOB"
from ZHISTORYITEM
left join ZMIXINMAPITEM on ZMIXINMAPITEM.Z_PK=ZHISTORYITEM.ZMAPITEM

When examining the output, I was perplexed by the lack of results, which is when I realized that number of 15 stayed constant no matter what I searched for. It appears to be transactional in nature. Also, I went through all the coordinates and realized that the Type “coordinates of search” will not show as “navigation journey” unless selected.  For example, I searched for UMMC (no longer part of this database in my final dump, but the “coordinates of search” persist. The one set of coordinates is for the University Medical Center in Maryland (the one I navigated to) and the other a University Medical Center in Mississippi, which I never selected.

The good news – GeoHistory.mapsdata has the historical searches made in iOS13! If you do not see these in the MapsSync_0.0.1 database, go back and examine the protobuf for locations of interest. Below we can see the searches for UMMC, which are no longer in MapsSync_0.0.1 exist here.

Protobuf View in PA

What about those BLOBS stored in “zrouterequeststorage” you ask? Well, they store your starting location and your final destination. Pretty important, right? This is the literal journey.

BLOBS embedded in Apple Maps
BLOBS embedded in Apple Maps

These BLOBs are protobufs and a special shout out to Jon Baumann who stayed up late to fix his script for me. You can find his script here to parse these nasty buggers. https://github.com/threeplanetssoftware/sqlite_miner/tree/protobuf

Here is some sample output of my file. Note that it isn’t perfect (he worked on this in minutes) and may have false positives.

SQlLte-Miner-.pl output

Protoc can be used to look at the protobufs. And there are many scripts to help. One recommended by the Cheeky4n6Monkey is https://github.com/mildsunrise/protobuf-inspector.

Another consideration is going back into your tool and searching around. Cellebrite Physical Analyzer has a built in button to search in binary blobs. I did two searches here. One for my home street (not sharing that here) and one for a location I navigated to/searched for (chantilly).

Searching Binary BLOBS in PA

Another option is to convert the BLOBS from the query provided above to Hex so you see the output and are alerted. Again, this is a preference thing. Thanks Jared Barnhardt for the suggestion here!

SELECT
ZHISTORYITEM.z_pk AS "Item Number",
CASE
when ZHISTORYITEM.z_ent = 14 then "coordinates of search"
when ZHISTORYITEM.z_ent = 16 then "location search"
when ZHISTORYITEM.z_ent = 12 then "navigation journey"
end AS "Type",
datetime(ZHISTORYITEM.ZCREATETIME+978307200,'UNIXEPOCH','localtime') AS "Time Created",
datetime(ZHISTORYITEM.ZMODIFICATIONTIME+978307200,'UNIXEPOCH','localtime') AS "Time Modified",
ZHISTORYITEM.ZQUERY AS "Location Search",
ZHISTORYITEM.ZLOCATIONDISPLAY AS "Location City",
ZHISTORYITEM.ZLATITUDE AS "Latitude",
ZHISTORYITEM.ZLONGITUDE AS "Longitude",
hex(ZHISTORYITEM.ZROUTEREQUESTSTORAGE) AS "Journey BLOB(hex)",
hex(ZMIXINMAPITEM.ZMAPITEMSTORAGE) as "Map Item Storage BLOB(hex)"
from ZHISTORYITEM
left join ZMIXINMAPITEM on ZMIXINMAPITEM.Z_PK=ZHISTORYITEM.ZMAPITEM
BLOB output as HEX – DB Browser for SQLite

I plan to keep digging into Apple Maps and will blog more as I find more information. For now, use this query if you dump a device running iOS14. Don’t be afraid to make it your own too! You will see many columns that I could not get to populate with valuable information.

For iMessage, you can now reply to a single portion of the conversation. The below screenshot shows you how this appears on the device.

Reply To Message

The database has two new columns called “thread_originator_guid” and “thread_originator_part” which appear to be what the tools are not yet parsing and is what alerts you to the message the reply was to. I have yet to determine what the “thread_originator_part” means.

SMS Reply To – DB Browser for SQLite
SMS Reply To – DB Browser for SQLite

Refer to the screenshot from the phone to put this all together. Until the tools catch up, here is a query that will get you part of the way. It’s not perfect, and I plan to try to merge them. Maybe one of my friends will help write a script for it (Calling Brigs, Ian and Cheeky4n6Monkey!). The query below has been updated for iOS14.

SELECT message.rowid,
chat_message_join.chat_id,
message.handle_id,
message.text,
message.thread_originator_guid,
message.thread_originator_part,
message.service,
message.account,
chat.account_login,
chat.chat_identifier,
case when LENGTH(chat_message_join.message_date)=18 then
datetime(chat_message_join.message_date/1000000000 + 978307200,'unixepoch','localtime')
when LENGTH(chat_message_join.message_date)=9 then
datetime(chat_message_join.message_date + 978307200,'unixepoch','localtime')
else 'NA'
END as "Message Date",
case when LENGTH(message.date_read)=18 then
datetime(message.date_read/1000000000 + 978307200,'unixepoch','localtime')
when LENGTH(message.date_read)=9 then
datetime(message.date_read+978307200,'unixepoch','localtime')
else 'NA'
END as "Date Read",
case when message.is_read=1
then 'Incoming'
when message.is_read=0
then 'Outgoing'
end as "Message Direction",
case when LENGTH(chat.last_read_message_timestamp)=18 then
datetime(chat.last_read_message_timestamp/1000000000+978307200,'unixepoch','localtime')
when LENGTH(chat.last_read_message_timestamp)=9 then
datetime(chat.last_read_message_timestamp + 978307200,'unixepoch','localtime')
else 'NA'
END as "Last Read",
attachment.filename,
datetime(attachment.created_date+978307200,'unixepoch','localtime') AS "Attachment Date",
attachment.mime_type,
attachment.total_bytes
FROM message
left join chat_message_join on chat_message_join.message_id=message.ROWID
left join chat on chat.ROWID=chat_message_join.chat_id
left join attachment on attachment.ROWID=chat_message_join.chat_id
order by message.date_read desc;

Bottom line – Apple isn’t rotten. The days I spend researching and blogging are for my family until I press submit! 😊 Please research and share! Validation is key. We all need to do it! Create test data and try it for yourself. If you find bugs, report them to vendors. If you find gaps, report them, and find someone who can build a tool to parse it. It’s our job in DFIR to educate and share. Happy hunting on iOS 14! And you may see this image coming to you publicly soon!

Leave a Reply

Your email address will not be published. Required fields are marked *