Mac Forensics — No One Said It Would Be Easy

TL;DR — Found out that a python based library to parse plist files was marking files as invalid while mac OS treated them as valid files.

It all started when I wanted to learn something new. I was looking for something to read and do, and then I stumbled upon David Cowen’s Sunday Funday. Although I’ve previously submitted an answer only once, I always scroll through the questions and try to find an answer. This time, the question was related to Mac OS 4n6 😲

On OSX Mojave, what information can you determine from the KnowledgeC database?”

Though for years I have been following some great #DFIR people that focus on MacOS Forensics, like Sarah Edwards (@iamevltwin) and others, I’m a bit ashamed to admit that I haven’t had the chance to do anything practical. I have never owned a Mac, nor have I worked for an organizations that uses them, so I’ve always had a reason for not doing Mac DFIR. Since I was looking to utilize my free time learning something, this was a great opportunity.

It took me some time to set everything up, and unfortunately, I didn’t get to do the Sunday Funday challenge. Luckily, someone else (@tunnaunglin) did. Dave tweeted his winning answer, and Yogesh Khatri (@SwiftForensics) suggested that he would integrate his findings into his tool — mac_apt.


I recalled that I had read about mac_apt when it was first published, and was enthused by the project. Being that it is also python based, I decided to try and contribute to the project by adding a plugin or two.

For those of you who are not familiar with mac_apt, you can watch the SANS talk to better understand how it works; the project’s description on GitHub simplifies it: “mac_apt is a DFIR tool to process Mac computer full disk images (or live machines) and extract data/metadata useful for forensic investigation. It is a python based framework, which has plugins to process individual artifacts…”

Generally, when I research DFIR stuff, I have this kind of process in my head:

  1. Find existing information — blogs, books, anything.
  2. Read what attackers / red teams do in the real world.
  3. Simulate malicious activity in lab if possible.
  4. Try to detect the malicious activity and left evidence using both live response tools and post-mortem tools to get some ideas.

So, I found this great post by Richie Cyrus who explained how he hunts malicious activity on Macs. His first example was detecting suspicious launch daemons (a common persistence technique used by attackers in the Mac OS world). In his post, Richie used osquery, which is a great live response tool.

When I went over the plugins list in mac_apt, I realized there is no plugin for persistence locations like LaunchDaemons, LaunchAgents, cron jobs, etc. So I decided to write a plugin of my own. I did exactly what Richie did, and installed a malicious backdoor on my Mac, and then I added a malicious LaunchDaemon and everything worked great, on the offensive side.

No Pain — No Gain

Of course, as with anything learnt for the first time, not everything works smoothly… I created an image of my OSX Mojave machine and ran my new mac_apt plugin against it. Unfortunately, I didn’t get any results. Classic. 😢

I investigated further and it turned out that the plist file I created with Empire was “invalid”. I got the following error: biplist.InvalidPlistException: XML or text declaration not at start of entity: line 2, column 0

I opened the file manually, and indeed there was an empty line in the beginning of the file, causing the library to determine it’s an invalid file.

the “invalid” plist file with an empty first line

That’s odd. I checked the LaunchDaemon technique I used and it worked… I even checked the source code of Empire. Although there is indeed an empty line at the beginning of the file, it works. I get a callback from the backdoor.

I Googled some information and found out a built-in MacOS utility named plutil. According to its manual page; “plutil can be used to check the syntax of property list files, or convert a plist file from one format to another”). Perfect.
Ran it against the persistence plist file and got a response that the file is OK.

So if the operating system says it’s OK, what is wrong with mac_apt?


I started debugging the error, and found out that mac_apt uses a library called biplist. It is a great library that wraps another library called plistlib, offering different methods to parse plist files; you can provide it a path or a file object and it will parse it for you. Alternatively, you can provide a string instead.

I loaded the file, stripped off the first empty line, into a string; and when I passed the string into biplist.readPlistFromString() it parsed it correctly.

Successful parsing of the “invalid” plist file

Great! Now I can write the plugin I wanted to.

Closing Notes

  1. Harlan Carvey and other great DFIR folks have already discussed the concept of tools “validation”, so I will not say a lot about it. I just want to emphasize how important it is, in my opinion, to understand the evidence before we start to use a tool that automatically parses evidence for us.
  2. I reported the issue in the mac_apt project page, and Yogesh already provided a fix! I will test it and hopefully send a PR with my plugin.
  3. I did a quick check, and it seems that biplist is being used by other macOS DFIR tools, which possibly use it wrongly. It’s worth checking further.
  4. That was a fun way to start doing macOS forensics. However, I noticed that there aren’t too many test images out there. So:
     a) If anyone can share some “test images”, that would be great. Please do!
     b) I’m thinking to manually “compromise” my virtual machine, perform
     malicious activity on it and image it. Is that something that can be useful for anyone? If the answer is yes — let me know and I will try to work on it.