OS X Anti-Forensics Techniques 2 - Assaulting OS X
Read previous part: OS X Anti-Forensics Techniques - How the Leopard Hides His Spots
Proceeding with presenting his research on Mac OS X anti-forensics techniques, the Grugq now delves into HFS+ file system attacks.
HFS+ Induction
So, I’m now going to give everyone a lightning-quick introduction to HFS+ file system. Here’s the introduction. HFS+ stands for the Hierarchical File System Plus; it came out with OS X; there’s some backwards compatibility stuff in there for OS-9 and earlier. It was very heavily influenced by HFS, which is just the Hierarchical File System, no Plus. The on-disk structure is actually quite complicated because they used B*trees; and B*trees are specific form of binary tree that, when it gets written out to disk, it’s a little bit annoying to deal with. If anyone is really interested in the technical specifications for this, the Apple Technical Note 1150 is actually very-very good, and I highly recommend it – makes great reading, you can take it on a train, have a nice cup of coffee… Maybe it’s just me, but they really write it quite well.
The components that I mentioned earlier: we have the header – in this case the header is called the ‘volume header’; a block is called a ‘block’; and a node is actually made up of different parts (the block lists are made up of extents which can be stored in a couple of different places, and the metadata is stored in several different catalog file entries). The catalog file basically contains your file system structure, the whole directory structure that you’re familiar with. And then the map itself is the catalog file entries.
One of the areas that you should not store data is between the end of the logicalSize and the end of allocated blocks. That’s what’s usually called ‘slack space’. Every forensics investigators knows how to find data there. Basically, that’s the only place that they know how to look, so if you tell them that you’re using slack space, this is where they’re going to go – they’re going to look at all of the blocks that have been allocated and they’re going to find the end of your user data and that space at the end; they’re going to look at that and be really excited if they find something. So, don’t put your shit there, like the anti-forensics toolkit inside Metasploit – that’s where it puts all of its data. Don’t do that, it’s stupid.
Okay, B*trees are used very-very heavily within the HFS+ file system. Basically, what a B*tree does is it’s a binary tree, where all of the leaf nodes are connected in a link list. The idea is that a file is divided up into nodes; each node has an address, you can point to it by indicating the address, it’s pretty straightforward stuff.
So, once again, I have a very cool illustration which I did not copy directly out of the technical docs. This is what a node actually looks like, this is kind of important. The key thing to look at over there is the part where it says “Free space.” You can cross that out and write in “Reserved for hacker usage only.” The idea with the B*tree node here is that you’ve got a number of records inside of there, and any unallocated space that isn’t being occupied by a record is available as free space that can be used later on.
HFS+ Attacks
Okay, so let’s break that. We’re going to look at specific attacks that we can do against HFS+, starting out with just file allocation attacks. As I mentioned, there are special files; you can do cool things with special files. One of them is there’s a special file called the ‘bad blocks file’. The bad blocks file exists to allocate blocks which contain bad sectors and prevent them from being used by user data. So you go to the extentsFile and you mark extents that hold bad blocks as belonging to the file number 5. So any extent that owed by catalog node ID5 is not flagged by the file system checker and it’s basically ignored by forensics tools, because, once again, the old bad blocks trick is the oldest one in the book, and it still works, particularly on the HFS+.
Similarly, you can do this with the allocation file. The allocation file has the space that’s been allocated for the bitmap, and the kernel will not actually look beyond the last element of that bitmap. But there’s nothing that tests that the size of the allocation file is exactly the right size to store that bitmap, so you can increase the size of the allocation file and put your data at the end there.
I mentioned that there was some backwards compatibility. One of the things that happens is older Mac OS 9 systems wouldn’t be able to access an HFS+ drive, so what they did is they put the HFS+ drive inside and HFS file system – that’s called an HFS wrapper. So you can actually have your HFS+ file system embedded inside an HFS file system – you get HFS file system inside HFS+. Everyone looks at the HFS+, but you actually have two file systems that you can do this stuff with. So you can actually use the HFS Wrapper for data storage yourself. So you can allocate additional space within the HFS Wrapper, particularly at the end of the bad blocks file. So the embedded HFS+ volume is marked as bad blocks within HFS. You can extend the size of the bad blocks file and then use the slack space at the end. Very straightforward stuff. This will work probably for the next few years, because even if you tell them what’s wrong with forensics tools, they don’t fix them. It’s not really part of their business to fix problems; it’s only to come out with new features and stuff.
Okay, those are attacks that we can do with allocation files. I haven’t implemented them yet because it’s actually really irritating to do allocation with all of the B*trees. I’ve spent most of my time implementing my B*tree code.
So, one of the things that you can do is a B*tree has a special type of node called a ‘map node’, which, once again, contains a bitmap to indicate which node within that B*tree has been allocated.There’s nothing that says the number of map nodes has to be exactly the right number to hold a bitmap that fits the entire tree. You can extend the number of map; you can add new map nodes and use those maps for data storage. So you can just add map nodes at the end of the linked list, and they’re not going to be accessed by the kernel because they would indicate nodes that go beyond to the end of the file, so they’re outside the scope of that B*tree – nothing to worry about. This is very-very easy to implement, but for some reason my code doesn’t work, so this demo gets skipped.
As I mentioned, there’s free space inside nodes; you can actually do data storage inside that free space. Once again, my code doesn’t work, so we’re going to skip this demo. But what I can show you is how it mostly gets up into the point that it gets written to disk when it stops working. It drove me nuts, I spent about an hour on it. At the very-very lowest layer I have, I can see the buffers that are supposedly getting written to disk and they contain all the data, and then when I read it back in – the data is gone. So I’m going to lodge a complaint with Apple saying that there’s something wrong with their disk driver that erases my data hiding attack before it gets down to the disk. I’m pretty sure that’s the only possible explanation at this point.
Read next part: OS X Anti-Forensics Techniques 3 - Expanding the Attack Space