Partitionierung eines komplett verschlüsselten Linux-Systems
Ausgangspunkt ist ein relativ weit verbreitetes Setup, bei welchem beinahe alle Dateisysteme in einem Crypt-Container (komplett 'md1' auf Basis von dm-crypt) liegen und somit ausreichend geschützt zu sein scheinen. Das Partitionierungsdiagramm verdeutlicht die gewählte Konfiguration:
Einzige Ausnahme bei diesem Setup ist das Dateisystem '/boot', welches unverschlüsselt auf einer relativ kleinen Partition liegt. Dort liegen:
- der Boot-Manager GRUB 2
- die Kernel und InitialRamDisks der installierten Betriebssysteme
Ein solches Setup sichert die Daten im verschlüsselten Bereich gut ab gegen Angriffsszenarien wie Diebstahl oder Verlust der Hardware.
Inhaltsverzeichnis
Warum sollte '/boot' geschützt werden?
Sowohl Boot-Loader als auch Kernel scheinen auf den ersten Blick unkritisch, weil sie keine geheimen Daten enthalten. Es gibt aber mindestens zwei Angriffsszenarien, welche über Umwege letztlich zu einer Kompromittierung der eigentlich schützenswerten Daten unter '/home' führen können. Beide führen über eine Trojanisierung des Kernels dazu, dass die Passphrase für die Entschlüsselung des Crypt-Containers abgefangen wird. Hierzu wird der bestehende Kernel unbemerkt ausgetauscht durch eine Version mit bösartiger Zusatzfunktionalität.
Beim nächsten regulären Boot-Vorgang wird dann die vom User eingegebene Passphrase unbemerkt abgegriffen und weiter gegegeben - ab hier sind die Daten im Crypt-Container ungeschützt vor dem Angreifer.
Die Angriffsszenarien:
- Es besteht physischer Zugriff auf das System ("Evil Maid"). Entsprechend vorbereitet reicht hierfür ein sehr kurzer Zeitraum aus.
- Start eines unsicheren Betriebssystems in einer Multi-Boot-Umgebung (in diesem Beispiel nicht gegeben). Auf diese Weise ist eine Attacke auch remote möglich.
Details:
- Linux boot loaders supporting full disk encryption?
- Pwning Past Whole Disk Encryption
- Bruce Schneier: "Evil Maid" Attacks on Encrypted Hard Drives
- The Problems with Full Disk Encryption
- Festplattenverschlüsselung (Wikipedia)
Schutzmaßnahmen
/boot auslagern
Ein erster (naiver) Ansatz wäre, die Boot-Partition ebenfalls zu verschlüsseln. Das scheitert aber daran, dass zumindest ein kleiner Bereich prinzipbedingt unverschlüsselt bleiben muss, sonst kann die Software nicht geladen werden. So könnte man zwar möglicherweise mit GRUB 2 den Kernel selbst in einen verschlüsselten Bereich auslagern, aber der Bootloader muss unverschlüsselt bleiben. Das würde das Problem somit nur verlagern und nicht lösen, weil ein Angriff über einen trojanisierten Bootloader den selben Effekt hätte wie mit einem trojanisiertem Kernel.
Dieses grundsätzliche Problem kann allein auf Software-Ebene nicht gelöst werden.
There's no security like physical security What you have to do is make it so its impossible to edit the kernel. To do so, you have to keep the kernel on you at all times. No, I dont mean sticking your laptop up your shirt to go to work, I mean installing your kernel and boot loader onto a USB stick that you can carry around with you around your neck or in your pocket.
Diese Tatsache berücksichtigend, werden Bootloader und Kernel auf einen USB-Stick installiert. Dieser spezielle Boot-Stick wird bei diesen Gelegenheiten verwendet:
- Boot-Vorgang
- Suspend-To-Disk
- Update von GRUB 2 oder Kernel
Ansonsten ist der Stick nicht gemountet und wird an sicherer Stelle aufbewahrt. Die Wirksamkeit dieser Sicherheitmaßnahme wird selbstverständlich durch die Sorgfalt bestimmt, mit der die verwendeten Boot-Sticks gegen unberechtigten Zugriff geschützt werden.
Bei Bedarf (und wenn in Zeiten von 'Prism' noch ausreichendes Vertrauen zu Hardware-Herstellern besteht) kann natürlich auch ein spezieller Boot-Stick mit Hardware-Verschlüsselung verwendet werden.
Einschränkungen
Auf den ersten Blick erscheint die Vorgehensweise umständlich und ist in Abhängigkeit von der verwendeten Hardware auch relativ langsam. Im konkreten Fall eines Notebooks fallen diese Kriterien aber im laufenden Betrieb kaum ins Gewicht, insbesondere weil das System relativ selten tatsächlich gebootet wird. Stattdessen kommt sehr häufig 'Suspend-To-RAM (STR)' zum Einsatz, bei welchem ein Bootvorgang nicht notwendig ist.
Hinweis: Suspend-To-RAM (STR) birgt ein gewisses Risiko. Hier wird der Inhalt des RAM aktiv gehalten, was zusätzliche Angriffsvektoren offen hält. Das Risiko besteht auch bei einem laufendem System und ist nicht spezifisch für diese Absicherungsmaßnahme, aber die Verwendung von STR verlängert den Zeitraum, in dem das Risiko besteht. Mehr Sicherheit bietet daher ein sauberer Shutdown oder auch STD.
Hingegen funktioniert ein 'Suspend-To-Disk (STD)' nur, wenn der Boot-Stick gemountet ist. Fehlermeldung, falls das nicht der Fall ist:
2013-07-12T12:15:45.284231+02:00 user-w520 systemd[1]: systemd-hibernate.service: main process exited, code=exited, status=1/FAILURE 2013-07-12T12:15:45.290516+02:00 user-w520 systemd[1]: Failed to start Hibernate. 2013-07-12T12:15:45.290862+02:00 user-w520 systemd[1]: Dependency failed for Hibernate. 2013-07-12T12:15:45.291088+02:00 user-w520 systemd[1]: Job hibernate.target/start failed with result 'dependency'. 2013-07-12T12:15:45.291316+02:00 user-w520 systemd[1]: Service sleep.target is not needed anymore. Stopping. 2013-07-12T12:15:45.291584+02:00 user-w520 systemd[1]: Unit systemd-hibernate.service entered failed state 2013-07-12T12:15:45.291777+02:00 user-w520 systemd[1]: Stopping Sleep. 2013-07-12T12:15:45.291952+02:00 user-w520 systemd[1]: Stopped target Sleep.
Deaktivierung von Firewire
Ein weiteres Angriffsszenario auf den Schlüssel besteht bei lokalem Zugriff über einen Firewire-Anschluss. Dieser soll einen direkten Zugriff auf das RAM und damit auf den Schlüssel ermöglichen. Sicherheitshalber wird Firewire daher deaktiviert:
user-w520:~ # echo "blacklist ieee1394" >> /etc/modprobe.d/50-blacklist.conf user-w520:~ # echo "blacklist firewire-core" >> /etc/modprobe.d/50-blacklist.conf
Hinweis: Unter Opensuse 12.3 befindet sich out-of-the-box dort schon ein Eintrag:
# If you really need firewire direct networking, then remove this entry blacklist eth1394
Prozessbeschreibung Systemupdates
- Während eines Systemupdates von 'grub2' oder 'kernel' muss der Stick gemountet sein (s. Abhängigkeit zum Patch-Prozess).
- Unmittelbar nach dem Update wird im gecrypteten Bereich ein Image des Sticks als Archiv abgelegt, woraus zu jedem beliebigen Zeitpunkt ein neuer Boot-Stick erzeugt werden kann:
user-w520:~ # today=`date +%Y-%m-%d`; f=/home/user/sys/boot/boot-$today.img; dd if=/dev/sdc of=$f 3915776+0 records in 3915776+0 records out 2004877312 bytes (2.0 GB) copied, 99.6817 s, 20.1 MB/s
Achtung: |
Unbedingt die Benennung des richtigen Devices beachten. Die Ausführung von dd auf das falsche Laufwerk kann alle Daten dort zerstören! |
- Es müssen alle (sicher deponierten!) Boot-Sticks aktualisiert werden:
user-w520:~ # dd if=$f of=/dev/sdd 3915776+0 records in 3915776+0 records out 2004877312 bytes (2.0 GB) copied, 625.637 s, 3.2 MB/s
Abschluss:
user-w520:~ # gzip $f
Verlust des Boot-Sticks / Verdacht auf Kompromittierung
Im Notfall (Verlust des Boot-Sticks oder vermutete Kompromittierung) kann ein passender Boot-Stick auf Basis des im gecrypteten Bereich abgelegten Images neu erstellt werden. Hierzu kann ein beliebiges, frisch heruntergeladenes USB-Image einer Live-Distribution zum Booten verwendet werden (checksum prüfen!), welches sowohl dm-crypt als auch lvm unterstützt.
Vorweg: Der Live-Stick von OpenSUSE 12.3 / KDE beherrscht das Mounten des verschlüsselten Bereiches schon out-of-the-box. Hier soll zur Verdeutlichung trotzdem der gesamte Prozess dokumentiert werden. Vorweg werden die Schritte des Live-Sticks zurückgenommen:
linux:/home/linux # losetup --detach loop0 linux:/home/linux # mdadm --stop /dev/md127 mdadm: stopped /dev/md127 linux:/home/linux # losetup -a
Das RAID1 aktivieren:
linux:/home/linux # mdadm --assemble --scan mdadm: /dev/md0 has been started with 2 drives. linux:/home/linux # cat /proc/mdstat Personalities : [raid1] md0 : active raid1 sda1[0] sdb1[1] 488385344 blocks super 1.0 [2/2] [UU] bitmap: 0/4 pages [0KB], 65536KB chunk unused devices: <none>
Cryptbereich entschlüsseln:
linux:/home/linux # losetup -f /dev/loop0 linux:/home/linux # losetup /dev/loop0 /dev/md0 linux:/home/linux # cryptsetup luksOpen /dev/loop0 md0 Enter passphrase for /dev/md0:
LVM initialisieren und Mounten:
linux:/home/linux # vgchange -a y 6 logical volume(s) in volume group "system" now active linux:/home/linux # lvs LV VG Attr LSize Pool Origin Data% Move Log Copy% Convert backup system -wi-a---- 100.00g home system -wi-a---- 310.00g os1 system -wi-a---- 10.00g os2 system -wi-a---- 10.00g os3 system -wi-a---- 10.00g swap system -wi-a---- 16.00g linux:/home/linux # mkdir /root/home linux:/home/linux # mount /dev/mapper/system-home /root/home
Jetzt kann das archivierte Image auf den Boot-Stick geschrieben werden:
linux:/home/linux # dd if=/root/home/user/sys/boot/boot-2013-07-11.img of=/dev/sdc 3915776+0 records in 3915776+0 records out 2004877312 bytes (2.0 GB) copied, 269.878 s, 7.4 MB/s linux:/home/linux # umount /root/home
Achtung: |
Unbedingt die Benennung des richtigen Devices beachten. Die Ausführung von dd auf das falsche Laufwerk kann alle Daten dort zerstören! |