macOS Incident Response | Part 1: Collecting Device, File & System Data

In previous posts, we’ve looked at how malware persists on macOS, taken a practical tour of macOS malware hunting techniques and also discussed techniques for reversing macOS malware. One area that we haven’t discussed so far, and which we’ll offer an introduction to in this and subsequent posts, is macOS post-breach or post-infection incident response. We’ll get started today, in Part 1, by explaining how to quickly gather up vital data about file events, system configuration and the machine’s current environment. In later posts in this mini-series on macOS incident response, we’ll look at discovering user activity, retrieving things like browser history, email messages, notifications, and application usage, among other things. 

Throughout, we will learn about many of the hidden logs, text files and databases that are littered across both the user and system domains that can reveal suspicious or malicious activity, and we’ll see how to write our own scripts to collect and analyse that data along the way. Although this is a vast subject, we hope this short series will serve as an introduction and give you a taste to learn more, so let’s get started!

Getting Started With Incident Response

When I’m dealing with a Mac that’s known to be compromised, the first step is to consider the client’s situation and the potential nature of the breach. For example, if the device may have been used in a crime or could become part of a criminal investigation, I would recommend the client to use a digital forensics lab that can image the device and recover artefacts from memory without polluting the evidence. This is quite a different process from what we will cover here, which is more akin to a SOC team investigation to determine what an intruder or a malware infection may have done that has not already been logged by detection software. Has there been lateral movement, has data been exfiltrated, has there been system manipulation? Are there other indicators of attack or compromise that we haven’t yet discovered? These are the questions that we want to set out to answer as quickly as possible in order to protect the business.

Let’s assume for the purposes of our scenario, then, that an employee has brought us a machine after discovering and removing a malware infection. The machine is still powered on, and we have the necessary credentials (and authority) to examine the machine fully. 

Say Hello to Sysdiagnose

With that out of the way, let’s set about collecting some initial information. Typically, investigators will want to list things like the system version, currently running processes, network configuration, Bluetooth set up, mounted volumes, install history, system log and much more besides. You could invest quite some time writing your own custom scripts to collect that and other information (we’ll do a bit of custom script writing later in this series), but if you have direct access to the machine you can save yourself a lot of work by leveraging the built-in sysdiagnose tool provided by Apple. 

The sysdiagnose tool was not designed for security or incident response purposes. Apple wrote it for macOS beta testers as a means of collecting just about everything they could ever want to know about a Mac when investigating OS bug reports. But for that reason, it’s ideal for our purposes, too. Here’s an image showing just some of the data that it collects.

image of sysdiagnose output (some of it)

What’s even nicer, from the point of convenience, is that if you have physical access to the machine you can kickoff the report simply by pressing this keychord:

Control-Option-Command-Shift-Period

If you get it right, you’ll see the display briefly flash indicating that the process has begun. 

If using the keychord is a problem for any reason, head over to the Terminal app. There are a bunch of command line options you can specify (see man sysdiagnose page), but for our purposes we will just run it in vanilla mode. Enter the following, type the admin password, and confirm that you want to proceed when prompted:

$ sudo sysdiagnose

In this case you will not see the display flash. 

Regardless of which way you invoke the tool, it’ll take a few minutes to complete, so you might want to take the opportunity to make a coffee, walk the dog, feed the cat, or while away the time as you see fit until sysdiagnose has done its thing. 

Exploring Files Collected by Sysdiagnose

When sysdiagnose has finished, it’ll pop a Finder window showing you the compressed result. Copy it off to your local machine, then double-click it to unpack it and have a quick scroll through what’s been collected. Yes, there’s a lot of juicy stuff in there: everything from a full ps to netstat, kextstat, system_profiler, top, Wifi scans and much, much more.  

image of sysdiagnose unzipped

When working with large amounts of text files I like to use BBEdit, which offers many useful functions for quickly searching and manipulating multiple files. The features I’ll use are all available in the free version, so if you don’t already have a copy of BBEdit just go ahead and download the free demo. Of course, if you have your own way of working with large sets of files, that’s fine, too. 

If you have BBEdit in the Dock, grab the sysdiagnose parent folder in the Finder and drag and drop it on top of the BBEdit Dock icon. When the project view opens up, scroll down to the logs folder in BBEdit’s Sidebar, click the disclosure triangle and scroll down again. You should see useful things like Install.log and InstallHistory.plist among many other goodies. 

Still in the logs subfolder, find the folder SystemExp, descend into that and open up the folder named “Dock” (followed by a date and timestamp). In here, you’ll find useful stuff such as CachedWindows.txt, which might tell you a little about the user’s recent activity (although much more to come on that in the following post!). 

image of CachedWindows

Also, take a look at dockextras.txt file, which may include info on things like the last time the user connected to Facetime, Messages and a bunch of other apps. 

image of Facetime Connection

Interlude – A Note About Timestamps

Before we move on, a note about the timestamps you see here, as you’ll encounter these elsewhere in macOS logs. Timestamps like this

587381138.016775

may look like Unix epoch timestamps (that is, seconds since 1/1/1970), but if you try to convert them using Unix epoch time you’ll get nonsense dates. These are actually Cocoa timestamps, which are similar but the seconds are counted since 1/1/2001. To convert them, add the difference between Unix and Cocoa start dates in seconds (that’s a fixed integer of 978307200) and use the date command line utility with the -r switch. We remove the fraction of a second and just deal with the whole integer, like so:

$ date -r $((587381137 + 978307200))

image of cocoa timestamp

That returns the more human-friendly date of Tue 13 Aug 2019 16:25:37 +07 from the Cocoa timestamp.

Finding Traces of Malicious Activity

Just below the logs folder you should see a file lsappinfo.txt. Click on it to load it into the main editor window. This file contains a lot of useful data about currently running applications, but even more useful for incident response – when we’re likely faced with a situation where malware has been and gone – is to look in the two files below, the admin (501) and root (0) dumps of lsregister. These are dumps of the databases held by Launch Services and contain detailed information about every application that has been available to the user.

Let’s walk through a practical example of how we might use this information to learn more about an infection.

If you scroll through lsregister-0.txt, you’ll notice each record has a path field and many have a CFBundleIdentifier field. To make a cursory examination of this file, I’ll use BBEdit’s ‘Process Lines Containing’ function (from the Text menu) and copy all lines containing CFBundleIdentifier to a new document. 

In the resulting text window, I’ll use the same function only this time I’ll delete all lines containing “com.apple” to narrow down my search (as we’ve pointed out before, some malware likes to disguise itself by using the “com.apple” label, so bear that in mind).

image of process lines

On my suspect device, this gives the following results. The highlighted ones will stand out to anyone familiar with macOS malware. There’s a bunch of commodity adware/PUP programs, but the ones in red are particularly interesting.

image of Suspicious BIDs in LSRegister

Let’s see what more we can find out about them. We’ll start with the bottom one, since that kind of bundle identifier is a non-standard pattern rarely used by legitimate software. Using BBEdit’s Multi-File Search function (Shift-Command-F), we can rapidly search through all the files collected by sysdiagnose for this identifier and see what else is known about it. 

image of multi file search

Add the identifier to the “Find” field and choose “Frontmost project” from the “Search in:” panel below. Then click ‘Find All’.

image of Finding IoCs

Our search results have revealed the Path, full App Name and team ID (aka “Developer Signature”). But further investigation on the machine shows no evidence the application still exists. After trying searches on VirusTotal and other public search engines, the teamID led us to a Russian-language stackoverflow post.

image of Russian stackoverflow adware

It turns out that the developer signature was used to sign an “app” that was in fact a Bash script bundled in an Application wrapper. It looks very much like a variant of OSX.Shlayer. There’s a high probability that the item found on our machine was a variant of the same malware, given that they were both signed by the same developer.

Returning to our list of labels, note that the second item, com.lights.Oblivion, is a bundle identifier associated with OSX.CrescentCore.

And what about the other highlighted item, com.ableton.live? Ableton Live is a legitimate commercial program, but there’s also cracked versions on the internet that are used for cryptojacking. Again, using the Multi-File search, we can find more info in the sysdiagnose folder. This time a result in the install.log reveals that the app was delivered in an unsigned .pkg. Since there is no chance that a company like Ableton would be distributing their software without proper code signing, there’s a strong likelihood that this package is malware. 

image of ableton live cracked

It seems our user’s machine has seen quite a lot of action!

While the above example isn’t particularly methodical, it does hopefully give you an idea of what you can do with such a vast amount of data and a few multi-file searches. 

One Log To Rule Them All

Among the many other files worth exploring in the sysdiagnose folder, there is one other that deserves special mention. Scroll down (either in BBEdit or Finder) to a file called system_logs.logarchive.

image of logarchive

As the name suggests, this is a collection of macOS system logs, the sort that are typically viewed in the Console.app. The file is actually a directory, but its contents are unreadable in BBEdit; however, double-clicking it in BBEdit will open it in the Console.app. You can also read this format with the log command in the Terminal. The latter is a far more powerful and effective tool for investigative work, but it does take a little practice to master. As there are many good guides on the log command, such as here and here, as well as the man page itself, we won’t go into details here. However, there are a couple of oddities about the “unified logging” system that I haven’t seen covered elsewhere and which are worth being aware of. 

First, note that the system_logs.logarchive file collected by sysdiagnose only contains a subset of the logs available. You can see the range of information collected by using the stats command. For example, 

$ log stats --archive <path to logarchive file> --overview

image of log stats sysdiagnose

In this case, we see logs collected from August 15th to 20th. Now let’s run the same command on the machine without specifying the name of the logarchive file in the sysdisagnose folder.

$ log stats --overview

With no logarchive file specified, the command returns the stats for the main system log datastore held on the device.

image of log stats live

That’s quite a lot more (and also quite a lot larger!) and covers around 30 days worth of logs, from July 22nd to August 21st. To collect all the log info, run a separate collection command.  Be sure to specify a destination that is safe to write to (such as a connected device or quarantined folder) as by default the collect verb will save to the current working directory.

$ sudo log collect --output <path to dst>

The other oddity of this tool is that if you run the stats command on your newly collected log file, you may find it contains logs reaching even further back in time than the previous output of --overview indicated. In this case, the collect command appears to have reached back an additional 4 days, to 18th July.

image of logs stats archive

The cause of these oddities is unknown (at least to me) – whether it’s a bug or intended behavior – but the vagaries of the log command are worth bearing in mind. 

Exploring fs_usage for File Activity

One other file we’ll mention in the sysdiagnose folder before moving on is fs_usage.txt. This gives you a capture of file activity when you ran the sysdiagnose utility. It is useful to see what was occurring at the time of collection. You can quickly parse fs_usage.txt to get a list of every process that was involved in file activity. Try to cd into the sysdiagnose parent directory, then use something like the following to uniquely list processes that were interacting with the file system:

$ awk '{print $NF}' fs_usage.txt | cut -d. -f1 | sort -u

AirPlayXPCHelper
CoreServicesUIAg
Electron
Finder
Opera
Slack
...snip...
Telegram
UserEventAgent
WireGuardNetworkExt
WireGuardNetworkExtension

We can do something similar to quickly get a list of all file paths that were accessed. Note we’re grepping out files accessed by sysdiagnose itself to ignore our own activity:

$ awk '{print $0}' fs_usage.txt | grep '/' | sort -u | grep -v -i sysdiagnose

However, as fs_usage only records file activity at the time we ran the utility, we need something better to provide historical records of file events. 

FSEvents – Old, Not Obsolete

Fortunately, such records of file system events are created in a hidden folder at the root of each volume or disk image. 

/.fseventsd

You can easily toggle visibility of this and other useful hidden folders in the Finder by using the keychord:

Command-Shift-Period 

image of fsevents Finder

As we see in the image above, this folder is protected, so we will need to drop down to root on the command line to inspect it.

image of fsevents terminal

The .fseventsd folder contains data files compressed with gzip. Although we could manually unzip each file, hexdump it or extract the printable characters with strings, that all requires a lot of labor and the results are likely to lose context. A better solution is to use the free tool FSEventsParser. This has the ability to create both SQL database and spreadsheet output, giving us access to much more powerful queries and analysis. 

Running the tool in its most basic form requires specifying the source and destination folders (more recent versions also require the -t switch and either folder or image for a value). Depending on the number of records, this may take some time.

$ python FSEParser_V3.3.py -s -t folder /.fseventsd -o /Users/sentinel/Desktop/FSEvents_Out

image of FSEParser start

The output, however, is well worth it. With FSEvents, we can conduct queries such as which files were sent to the Trash, what devices were mounted, which files were accessed or what websites were visited on a particular date. 

image of file system events parser sql

Like the unified logs, .fseventsd will only reach back a limited timespan as the records are continually churned to save space. How far back depends on a number of factors, including how active the system is, but if your suspicious events occurred close enough to the collection time, you may well have some extremely rich data that you can mine for evidence of malicious activity. 

Be aware that activities like updating the OS will wipe out existing logs in the .fseventsd folder (you can use the install.log in the sysdiagnose folder to determine when the most recent update occurred), and it’s also not unheard of for some events to fail to be recorded at all, such as during especially heavy I/O activity.

Another issue to bear in mind is that users can deliberately prevent the system from recording FSEvent activity by creating a touch file inside the .fseventsd folder.

$ sudo touch /.fseventsd/no_log

What all that means is that you can’t assume something didn’t happen just because you didn’t find a record of it in .fseventsd. However, what you do find can often prove extremely illuminating.

Conclusion

In this introduction to incident response on macOS, we’ve taken a look at three built-in tools – sysdiagnose, unified logging and FSEvents – that can help you quickly collect device, file and environmental data about a Mac. Due to the breadth of the subject, there’s a lot we didn’t cover here, but hopefully we’ve given you enough of a taste to explore further. In the next post in this series, we’ll take a look at some of the hidden databases that reveal user activity. See you there!


Like this article? Follow us on LinkedIn, Twitter, YouTube or Facebook to see the content we post.

Read more about Cyber Security