Friday 28 May 2021

iOS / macOS - Tracking Downloads from Safari Without Downloads

This week I got some huge news! This blog was nominated for a 4:cast award for Blog of the Year! I'm incredibly honored for this nomination! It also spurred me to remember I had a bunch of posts I wanted to work on but the last few weeks have been packed with teaching and work. Today I'm going to talk about a methodology for how to track files that have been downloaded from the Safari browser on iOS or macOS. 

Safari is an interesting beast when it comes to its storage. Apple lauds the browser as "Safe and Secure" and this default browser on the macOS and iOS ecosystem can cause examiners some headaches due to how long it chooses to keep its data. For more information on preferences for macOS and how this is controlled, see this post I did previously,

While the methods to track data in macOS and iOS are similar, there will be a slight difference depending on what you're working with and looking for. Let's start with macOS. 


First things first. macOS will only keep Safari downloads for 24 hours by default. This is obviously problematic. In addition, it only tracks the last 20 files so if your user has downloaded more than 20 in the last 24 hours, again, harder to track. The Downloads.plist file found within the path: ~/Library/Safari/ will store this information. 

When a file is downloaded in Private Browsing mode, the Downloads.plist is still used, but stores a value within it called "DownloadEntryRemoveWhenDoneKey" which will be flagged as True. This means that files that are downloaded will immediately be cleared even if within the last 24 hours. 

Again by default (set within the Safari preferences), the downloads will land in the ~/Downloads/ directory. So looking here is a good place to start. However, before we just jump here, we might want to also consider what happens to a file when it's downloaded. Essentially, downloading a file on macOS/iOS works like this: 

1. Container is created. Container is named the name of the downloaded file with ".download" at the end of it. Container will live in the directory where the file is supposed to be downloaded.
2. Info.plist file created within the container containing matching information from the Downloads.plist file. 
3. File data streamed into the ".download" container. 
4. Upon completion, data moved from .download container (folder) into appropriate directory. 
5. macOS's GateKeeper will quarantine the file and scan it creating an entry in the quarantine database. 

Based upon the above logic, there are a couple of things we can now start looking for. 

Quarantine Data

Using the "" database found within ~/Library/Preferences, information can be tracked to find what files landed on the system that were scanned by GateKeeper. Examiners should look for the package name containing "" because depending on HOW the file was downloaded the data under application name may reference either "Safari" or others including "" The information can store the original download URL as well as the displayed URL and when it was "Quarantined" which will be extremely close to the finished date of the download. 

To be honest, this can be hit or miss. I find that if a user is actively opening files they download it may get cleared from the Quarantined events, but not always. It does, however, last longer than the standard 24 hours of the Downloads.plist file in many cases. 

A note about files downloaded in Private Browsing mode. Files downloaded within this mode will still be checked by GateKeeper, however, it will not store the download URL of the file. It will however still store its "Quarantined File Identifier" which is going to be important in tracking what file that was. 

File System Events

Since examiners now know the process of the file, we can actually use the File System Events tracked by both iOS and macOS to find out some information. It's handy when you have a starting date and time, so using an event like Quarantine Events to gather when a file was downloaded (even if you can't see what the file was or where it came from like in a private browsing record), you can use this as your launch point. 

Filtering your file system events from that start point, you may see files created in the same timeframe on the system, but remember, files are downloaded into a container that ends in .download. 

By reviewing these records, examiners can see how the file system events are tracking the flow of the downloaded file originally listed above. The "Important" folder is created, the .zip and .plist file created inside, then when complete, the .zip is moved out, and the .plist is destroyed as well as the .download container. [NOTE: These events can happen quickly in small files and creation/deletion may happen within the same recorded event]

Files that were not completed will have a similar structure but without the final removal events. 

These events can also help to show when a file was moved from the downloads directory to a new location. Now that we can track that a download occurred a couple of different ways, can we match up records in the Quarantine Events to the file that was downloaded? In some cases, yes!

Extended Attributes

macOS will record extended attributes to files downloaded. This will include in many cases what browser was used to download the file as well as in many cases the URL that the file was downloaded from. A Quarantine Event GUID is also embedded into the Extended Attributes metadata. Now this information can also be tracked with Spotlight Metadata as well, however, files that are downloaded in Private Browsing mode will not have that spotlight metadata. 

Let's compare two files from the downloads directory. The first was downloaded with Safari NOT in private browsing mode. Here's one from my local system where I downloaded the file with Safari without using private browsing mode. By looking at this, you can actually see the value kMDItemWhereFroms which lists where this file was downloaded from: "" 

The extended attributes of the same file can store this information as well. If the data is living in a directory where indexing is not done, this can still reveal the information. However, the information in the extended attributes can also store the quarantine information. While we may not be able to track where the information was downloaded from (not tracked in files downloaded from private browsing mode), we can use the quarantine information to help show it came from Safari and that it was private browsing. 

For a file that is downloaded within private browsing, spotlight metadata may not show as much. However, we can still track the information that shows that this file, "Important" was downloaded from the Safari browser and it has a GUID. This can be matched to the Quarantine Events artifact to see its match (if it is still there)!

macOS WrapUp: 

So to summarize, when tracking downloads, a good methodology is to check in the following locations: 

  • ~/Library/Safari/Downloads.plist
  • Check the Safari Preferences to see where the downloads are default going to. 
  • Use File System events looking for ".download" records to find data relating to files downloaded from Safari. 
  • Use quarantine events to find that files are downloaded using Safari
  • Use extended attributes metadata to look for the events with Safari.


Now iOS can be a slightly different beast. It still has some of the same functionality we can apply if we know where to look. When downloading files, the Downloads.plist file is still going to be used but users can't control as many preferences. The Downloads.plist file is going to be found within the Safari's app directory (not the Library/Safari directory as the browser history is). 

The same information is stored but note the Saved to Path. This is the default storage location that will send the data to the "iCloud Drive" area of iOS. Which, honestly, is interesting. It takes your download and then tries to send it back to its own cloud storage. 

Now these downloads are also not tracked forever. There is also not any way to have preferences to change how long these are going to be kept. 

File System Events:

In a similar manner to the macOS Safari downloads, when a file is downloaded in iOS/iPadOS, the file is stored within a .download container (folder). This folder is not contained within download target directory like in macOS, but is stored within a folder within the Downloads folder (that the plist lives in). 

This folder is named with a GUID which will match the "Download Identifier" in the Downloads.plist file. The data gets placed into a [Filename].[ext].download folder within a folder named the download GUID then moved to the final directory on successful download. 

No info.plist file here unfortunately. 

Files that are incomplete downloads will still live in this directory. Now the interesting thing is that a user can choose to store them within the iCloud Drive directory, but also can choose to store them on the "On My iPad" setting which puts them into a different directory. By looking at the file system events using the target filename, we can see where the file moved to. This time it didn't move to the Mobile Documents directory but to part of the data that tracks back to the iOS Files app. [For more info on the Files App, check out this post here]

The ID of this folder tracks pack to the "local storage" manager used by the Files app. which can be seen in the "" within the root of this storage container. 

iOS WrapUp: 

So as you can see there's not as MUCH to track through with the downloads from Safari but may also be less common to find. Even when you don't find any Downloads.plist entries, by checking both paths: 
  • /private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/Downloads
  • /private/var/mobile/Containers/Shared/AppGroup/B00E5705-4543-4123-9309-0F6D70BE27C6/File Provider Storage/Downloads

By then working backwards to confirm these were downloads, using File System Events may help to track that they started in the Safari/Downloads/ directory. 

Final Wrap-up: 

Whew! That was longer than I originally intended. Once again the big thing is that just because the "Downloads.plist" file is empty doesn't mean you can't track the data in other ways at times. Hopefully these methodologies of where to turn can be useful to anyone reading! Again, big thanks for anyone reading this who nominated me for a 4:cast award and if you feel it's deserved, I'd love to earn your vote again for the award itself! If you're so inclined you can go vote here:

1 comment:

  1. Wanted to drop you a comment and say thank you for your blog!

    Recently believe I ran into a bug on an application I use that shares your file path but I wanted to be sure it was an error before I told the developers.

    I’m still not sure it is - and your blog is going to help me figure that out as I am completely unsure as to what I am looking at LOL.

    So thank you so much. Keep writing and congratulations on your nomination.