Last night I gave a presentation at the Tucson Computer Forensics and Information Security Meetup group titled Filling Volumes, Bypassing Limits, and Hiding Data with HFS+ and OS X. The group is hosted by Mari DeGrazia and incredibly fun. Be sure to check out her blog at http://az4n6.blogspot.com. I talked about a lot, went in to great detail in some areas and simply glanced over others. All of this is within the context of OS X and HFS+. I wanted to post, at minimum, about how to execute what I’ve found. This is that post.
Here’s the short and sweet version:
- File attributes have a maximum size of ~256K when locally stored.
- You can purposefully hide files in file attributes of other files for later reconstruction.
- There is no limit to the amount of attributes a file can have.
- You can saturate a volume by systematically creating file attributes for a single file and filling them with data.
- You can bypass the artificial OS X Server Network User home directory storage limit by storing data in file attributes.
- You can saturate the volume which OS X Server is storing the Network User home directories on by systematically creating file attributes for a single file and filling them with data.
File attributes have a maximum size of ~256K when locally stored.
Among the first things I tried to do with file attributes was to store a massive amount of data in one. As I played around with writing attributes I found the size limit of one to be around 256K. You can (and should) play around with this using the xattr command with the -w hook and adjusting the input size. Keep an eye out for the ‘Argument list too long’ error to know that you have chosen an input size too large. If you are able to exceed 256K please let me know!
You can purposefully hide files in file attributes of other files for later reconstruction.
Apple does this frequently. For example: The Tags feature in Finder stores the Tags data in a binary property list. The binary property list is stored as a file attribute to the file which the tag(s) apply. I had made a directory on my Desktop and applied the red color tag to it. In the screen shot below we can print out the file attribute using xattr, reverse the hex output into binary with xxd, and convert it from a binary plist to an xml plist with plutil. The output is sent to STDOUT.
Another example of this is screen shots. By default when you take a screen shot using the native keyboard shortcut it will save the image to your desktop. Depending on the screen shot this may be a grab of the entire screen, a specific window, or a manual selection. Three file attributes that contain a bplist are created for the screen shot:
com.apple.metadata:kMDItemIsScreenCapture – Contains a true value to declare that it is indeed a screen shot.
com.apple.metadata:kMDItemScreenCaptureGlobalRect – Holds four values. The first two being positioning of the screen shot and the last two being measurements of the screen shot’s height and width. In my experience these values are half of the screen shot’s pixel width and height. For example, values of 762 and 549 would indicate an image that measures 1524×1098 pixels.
com.apple.metadata:kMDItemScreenCaptureType – Contains a value that is a record of the type of screen shot taken. (The entire screen, a specific window, or a manual selection.)
Here is a screen shot of the file attributes being listed:
You don’t have to hide bplists if you don’t want to. Here’s an example of a Microsoft Word document being stored in a file attribute and then later being retrieved.
If you’re going to hide files in file attributes I highly recommend .DS_Store files. As far as OS X/macOS and HFS+ are concerned they’re completely organic, frequent, and are created with a file attribute form the get-go. You could certainly split up a large file into ~256K chunks and store it in file attributes in an attempt to hide it.
There is no limit to the amount of attributes a file can have.
I hit a limit of about 256k for and individual file attribute but I have not hit a limit on the amount of attributes beyond the capacity of the volume itself. The largest volume I tested this on was 500GB, so it’s entirely possible that there is some sort of limit that I just didn’t reach. Just because I didn’t do it doesn’t make this fact – please let me know if you have a better way of testing this that we can both repeat.
You can saturate a volume by systematically creating file attributes for a single file and filling them with data.
Given the previous item it should be obvious that this is possible. You can verify this on a Mac running OS X/macOS. In the screen shot below I’ve created a 100MB HFS+ volume, attached the volume, created an empty file in the volume, and then created 401 file attributes that were each filled with random data.
You’ll get a noisy output printed to screen. Eventually it will finish and you’ll have output that includes xattr: [Errno 28] No space left on device: ‘/Volumes/HFSPlus/empty’ We have filled the drive with file attributes storing random, junk data!
Before anyone says anything – Yes I know I should have gotten a 512GB SSD in my MacBook Pro instead of 256GB. It’s a decision I regret but live with. (If you call that living.)
Here’s a few screen shots of how this looks from Daisy Disk – a great OS X/macOS utility to analyze disk usage and free up disk space on Mac.
Daisy Disk is doing exactly what it can. It’s worth noting that tools like GrandPerspective and Disk Inventory X report this the same way. These programs aren’t flawed – they’re just not taking file attribute size into account outside of the context of what amount of free space the volume is reporting as available. They are beautifully organizing the file system in a presentable way based on what the file system is reporting.
What would a user or system administrator think from looking at the disk usage reports? Where did all of the data go? Would they be able to easily track it down? 🙂
You can bypass the artificial OS X Server Network User home directory storage limit by storing data in file attributes.
Here’s a screenshot tour of an OS X virtual machine running OS X Server. I have enabled Open Directory, File Sharing, and created the Local Network User Wendy Testaburger. I have created a 500MB NetUsers volume and set that as the location for her home directory. I have set the limit of her home directory to 50MB.
On an OS X client I connected to the file share using wendytestaburger and his password. I attempted to copy the soundtrack to Splice, a great puzzle game. It’s over 50MB and less than 500MB. After 50MB is copied I’m given the error about space due to the artificial limit set on the OS X Server.
We can check the volume usage in OS X Server.
Some of the tracks were able to copy over before the artificial limit was hit. We have verified that the 50MB limit is being enforced. To bypass this limit we can perform the action that we took with the earlier disk image.
It finishes without error was we specified an amount of file attributes that did not completely fill the volume. We have bypassed the limit and have written more than 50MB to the volume. We can see that we have bypassed that artificial limit by again looking at volume usage in OS X Server.
Boom. What 50MB limit? If we wanted to be real jerks we could do the next item!
You can saturate the volume which OS X Server is storing the Network User home directories on by systematically creating file attributes for a single file and filling them with data.
This is essentially the same trick as above with an adjusted goal. Instead of simply bypassing the limit you could continue to create file attributes, storing data in each, to fill up the volume that hosts the shared directory. On Macs running OS X Server this is frequently the same volume that holds the system. This isn’t the case for our test environment. Let’s saturate the rest of our volume from the OS X/macOS client.
Once you start getting the xattr: [Errno 22] Invalid argument: ‘/Volumes/wendytestaburger/.DS_Store’ message on your screen you can kill the process. The work is done. Here is the result on the OS X Server:
The volume that contains the shared directory is full. Success!
- This all appears to work on APFS. Testing has been incredibly limited and things change. There are major differences with this new file system, it’s still in beta, and I want to make sure I don’t make statements that aren’t true after the release of macOS Sierra this Summer/Fall.
- This is an alternate data stream (ADS) but I hesitate to put that in the title. An ADS is typically synonymous with the concept of exploitation in Microsoft Windows. More specifically being able to execute a program from an NTFS file attribute to disguise itself as a whitelisted application. That’s not what’s going on here and it would be irresponsible to set the expectation that it is. It’s important to realize that an ADS is really just that – an alternate data stream.
- I reported this to Apple a few months ago and they were great to communicate with. They called me and were incredibly nice. If you find a bug the last thing on your mind should be “Does this company have a bug bounty program?” If you think you have something report it and have realistic expectations.
- I do have a deeper/forensic analysis of what is going on. I presented on this but have not yet made a blog post about it.
- I’d like to thank Mari DeGrazia and Matt Edmondson for helping me when I needed to run something by them. (And for being great people!)