Шифрование дисков предназначено для защиты данных в компьютере от несанкционированного физического доступа. Бытует распространённое заблуждение, что дисковое шифрование с этой задачей действительно справляется, а сценарии, в которых это не так, представляются уж слишком экзотическими и нереалистичными. В этой статье показано, что извлечение мастер-ключа шифрованного тома LUKS легко осуществимо на практике, и предложен (давно не новый) метод защиты.
Суть проблемы
Отдельно стоит остановиться на предназначении дискового шифрования. Действительно, когда физический доступ невозможен и данными владеет запущенная система, проблем никаких нет. Могут быть проблемы с безопасностью самой системы, но тут шифрование дисков никак не поможет. Дисковое шифрование должно оберегать данные, когда у любопытствующей стороны есть возможность получить доступ к дискам минуя систему, например физически подключив диски к своей системе или загрузив свою ОС на инспектируемом компьютере. Сценарий физического доступа — единственный сценарий, при котором дисковое шифрование имеет какой-то смысл.
Проблема состоит в том, что атакующий может незаметно вмешаться в цепь загрузки ОС и вынудить систему выдать ключи шифрования, как только она их получит при очередном запуске.
Такая атака требует лишь одного акта доступа к компьютеру: данные с диска можно скопировать совместно с подменой цепи загрузки, а потом расшифровать их, дождавшись появления ключа. В сравнении с незашифрованными дисками неудобство состоит только в том, что нужно озаботиться тем, как ключ будет передан, и дождаться запуска.
Далее перейдём к демонстрации такой техники на практике. Может оказаться так, что для её реализации атакующему потребуется меньше усилий, чем владелец системы затратил на настройку какого-то своего экзотического метода разблокировки дисков (например, удалённо).
Практическая демонстрация
Демо я проведу на примере виртуальной машины с Debian 9, на которой шифрование дисков было включено при установке системы.
Установка Debian 9 с шифрованием создаёт загрузочный раздел и раздел с шифрованным LVM. Снимок экрана установленной системы с запросом пароля расшифровки для наглядности:
Всё готово, можно приступать. Выключаем машину, копируем диск. В моем случае это выглядит так:
[root@dt1 ~]# virsh destroy debian9-boothack Домен debian9-boothack разрушен [root@dt1 ~]# cp -v /var/lib/libvirt/images/debian9-boothack.qcow2 ~ '/var/lib/libvirt/images/debian9-boothack.qcow2' -> '/root/debian9-boothack.qcow2'
Монтируем диск машины, извлекаем инитрамдрайв:
[root@dt1 ~]# mkdir /guest [root@dt1 ~]# guestmount -a /var/lib/libvirt/images/debian9-boothack.qcow2 -m /dev/sda1 /guest [root@dt1 ~]# cp -v /guest/initrd.img-4.9.0-9-amd64 ~user/tmp '/guest/initrd.img-4.9.0-9-amd64' -> '/home/user/tmp/initrd.img-4.9.0-9-amd64'
Распаковываем инитрамдрайв:
[user@dt1 tmp]$ mkdir unpacked [user@dt1 tmp]$ cd unpacked/ [user@dt1 unpacked]$ zcat ../initrd.img-4.9.0-9-amd64 | cpio -idm [user@dt1 unpacked]$ ls bin conf etc init lib lib64 run sbin scripts
Готово, можно редактировать инитрамдрайв. Зная, что машина имеет постоянное сетевое подключение, я хочу организовать зашифрованную отправку мастер-ключа после открытия дисков. Для этого мне потребуется:
- Утилита для шифрованной отправки по сети. Добавляю её в
/sbin
- Шелл-скрипт для извлечения ключа и отправки. Отправляется в
/scripts/local-top
и добавляется в список/scripts/local-top/ORDER
послеcryptoroot
. - Недостающий родной скрипт обработки событий udhcpc, чтобы запустить автонастройку сети прямо в рамдрайве, пользуясь встроенными средствами. Его законное место в
/etc/udhcpc/default.script
Исполняемый файл secsend собран статически, чтобы устранить зависимости от каких-либо библиотек. При обычных условиях сборка даёт на выходе файл размером 2,7 МБ, что довольно ощутимо по сравнению с размером рамдрайва — 62 мегабайта в распакованном виде и 20 в сжатом. Однако, при сборке всех библиотек и исполняемого файла с минималистичной musl libc размер выходного файла получается ~250 КБ и 120 КБ после сжатия UPX. Сам secsend просто читает стандартный вход, шифрует его cryptobox-ом из libsodium с использованием заданного публичного ключа Curve25519 и отправляет данные на заданный адрес по TCP. Его использование непринципиально для основной цели демонстрации, он скорее показывает что атакующий по сути ничем не ограничен: можно запускать код, который делает что хочет атакующий и как он этого хочет.
После добавления этих трёх файлов и редактирования ещё одного можно запаковывать всё обратно и возвращать изменённый файл на место:
[user@dt1 unpacked]$ find . | cpio -o -c | gzip -9 > ../initrd.img-4.9.0-9-amd64 125736 блоков [user@dt1 unpacked]$ sudo cp -v ../initrd.img-4.9.0-9-amd64 /guest '../initrd.img-4.9.0-9-amd64' -> '/guest/initrd.img-4.9.0-9-amd64' [user@dt1 unpacked]$ sudo guestunmount /guest
Потребуется некоторый сервер для приёма зашифрованного мастер-ключа, например такой (Python 3.5.3+). Запустив его с указанием секретной части ключевой пары, дожидаемся, пока условная жертва включит свой компьютер:
При включении виртуальной машины с зашифрованным диском всё внешне выглядит как обычно, ничего не изменилось:
А вот на стороне слушателя подключений появился секретный мастер-ключ:
С этого момента сама виртуальная машина с данными и её пользователь со знанием пароля шифрования уже не представляют интереса для злоумышленника. Особо отмечу, что смена парольной фразы не меняет мастер-ключ, которым зашифрован весь том. Даже если между снятием копии и отправкой ключа как-то затесалась смена парольной фразы — это не помеха. Воспользуемся мастер-ключом для открытия тома. Для этого преобразуем его 16ричную запись в логе в бинарный файл:
[root@dt1 ~]# echo 'fa0c53***********4bd8c' | xxd -r -p > master.key
Монтируем диски со снятой копии:
[root@dt1 ~]# modprobe nbd max_part=8 [root@dt1 ~]# qemu-nbd --connect=/dev/nbd0 /root/debian9-boothack.qcow2 [root@dt1 ~]# ls /dev/nbd0* /dev/nbd0 /dev/nbd0p1 /dev/nbd0p2 /dev/nbd0p5 [root@dt1 ~]# file -s /dev/nbd0p5 /dev/nbd0p5: LUKS encrypted file, ver 1 [aes, xts-plain64, sha256] UUID: fb732477-ef98-40b5-86a2-8526c349f031 [root@dt1 ~]# cryptsetup --master-key-file=master.key luksOpen /dev/nbd0p5 crackeddisk [root@dt1 ~]# pvs PV VG Fmt Attr PSize PFree /dev/mapper/crackeddisk debian9-boothack-vg lvm2 a-- 19,75g 0 /dev/sda3 dt1 lvm2 a-- <215,01g 8,00m [root@dt1 ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert root debian9-boothack-vg -wi-a----- 18,75g swap_1 debian9-boothack-vg -wi-a----- 1,00g root dt1 -wi-ao---- 215,00g [root@dt1 ~]# mkdir /hackedroot [root@dt1 ~]# mount /dev/mapper/debian9--boothack--vg-root /hackedroot/ [root@dt1 ~]# ls /hackedroot/ bin boot dev etc home initrd.img initrd.img.old lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var vmlinuz vmlinuz.old [root@dt1 ~]# cat /hackedroot/etc/hostname debian9-boothack
Данные извлечены.
Меры защиты
Как можно заключить — корень проблемы в запуске недоверенного кода. Вот небольшой обзор методик, которые стоит рассмотреть в контексте этого вопроса.
Шифрование загрузочного раздела
Некоторые дистрибутивы предлагают и такую возможность при установке (например OpenSuSE). В таком случае загрузочный раздел расшифровывается загрузчиком, а затем с него загружаются ядро и инитрамдрайв. Такой подход не имеет особого смысла по следующим причинам:
- Самый главный вопрос с подменой кода всё равно остаётся открытым. Только теперь подменять нужно будет загрузчик.
- Для загрузочного раздела важнее не конфиденциальность данных, а целостность данных. Обычное шифрование LUKS не предоставляет такой гарантии. Некоторая выгода здесь заключается только в том, что на таком зашифрованном разделе трудно сформировать осмысленную подмену.
- И шифрование LUKS2 с проверкой целостности (dm-integrity) тоже не защищает от вмешательств, потому что оно не даёт гарантий против атак, связанных с повторным воспроизведением секторов. Например, имея дамп такого раздела и конфиг загрузчика на нём, всё равно можно взять и откатить ядро на состояние, скопированное ранее. Это не даёт преимуществ конкретно в вопросе извлечения ключа (разве что если старое ядро было уязвимо и это можно каким-то образом использовать), это скорее довод в пользу бесполезности шифрования загрузочного раздела.
Использование TPM для хранения ключа шифрования и валидации безопасной среды загрузки
TPM — по сути криптопроцессор, который работает как безопасный анклав или смарткарта в системе. Секретные данные, зашифрованные с его помощью, могут быть расшифрованы только с помощью него и только на его условиях — когда сходятся значения PCR системы, которые зависят от состояния платформы и запускаемого в ней кода. Технология достаточно перспективная и может позволить реализовать безопасное шифрование в системе, не требуя ввода ключа (например, выполняя вход по отпечатку пальца или по несвязанным с шифрованием методам аутентификации). В идеальном случае он должен работать совместно с UEFI Secure Boot, запрещая расшифровку, когда конфигурация не сходится.
Однако в линуксе поддержка TPM пока находится в зачаточном состоянии. Загрузчик TrustedGRUB2 (приспособленный для работы с TPM загрузчик) не поддерживает UEFI и от этого пропадает весь смысл затеи. Кроме того наличие рабочего TPM 2.0 только сейчас начинает появляться в железе, зачастую вместе с обновлениями BIOS. Большинство материнских плат не имеют дискретного TPM-модуля, вместо этого TPM программно реализован внутри Intel ME. По всем этим причинам я пока не рассматриваю такую конфигурацию как рабочую и пригодную для широкого использования.
Использование UEFI Secure Boot для полного покрытия загрузочной цепи электронной подписью
Существуют дистрибутивы (Fedora, OpenSuSE) и одиночные решения, которые позволяют использовать Secure Boot в Linux. Однако, коробочные решения зачастую не обеспечивают целостность кода в цепи загрузки. Они предназначены преимущественно для того, чтобы Linux просто запускался при включенном Secure Boot. Обычно просто используется EFI shim, подписанный сертификатом Microsoft, который дальше запускает всё что угодно. Соответственно, при использовании внешнего сертифицирования покрыть подписью инитрамдрайв, который генерируется прямо в установленной системе, просто невозможно.
На хабре имеются статьи, которые предлагают использовать собственную PKI для подписи кода. Это позволяет подписывать всё, что нужно, самостоятельно и таким образом покрыть всю цепь UEFI > загрузчик > ядро и инитрамдрайв.
- Укрощаем UEFI SecureBoot — первая статья на хабре на эту тему, очень подробная.
- Используем Secure Boot в Linux на всю катушку — здесь особенно хорошо написано, почему Secure Boot с установленными сертификатами Microsoft эквивалентен его отсутствию.
Требуемый результат получается во второй статье. Подпись инитрамдрайва достигается слиянием рамдрайва и ядра в одно EFI-приложение, без использования загрузчика, и UEFI напрямую проверяет подпись сразу оптом. Оба руководства требуют массу ручной работы на каждой защищаемой системе.
Доступное решение
Мне встретился подход к полноценному внедрению Secure Boot, совместимый с общепринятой схемой загрузки и не требующий серьёзного вмешательства в систему: отдельный загрузчик, отдельный рамдрайв, отдельное ядро. UEFI проверяет подпись только загрузчика GRUB2, загрузчик имеет вшитый конфиг с ключом для проверки подписи и паролем администратора, и дальше проверяет ядро и рамдрайв. Подписанный загрузчик устанавливается параллельно со старым и при необходимости сохраняется возможность запуститься обычным образом, выключив Secure Boot. Разумеется, эта возможность должна быть закрыта паролем администратора в меню настроек UEFI.
Я решил автоматизировать процесс внедрения Secure Boot с собственным PKI и сделать его простым и независимым от дистрибутива насколько возможно. В результате получился вот такой набор из рецепта Makefile и утилит: https://github.com/Snawoot/linux-secureboot-kit. Для debian, ubuntu, fedora и centos весь процесс требует всего несколько команд.
Конкретно на примере Debian 9 установка выглядит примерно следующим образом (предполагая, что UEFI уже в Setup Mode):
apt update && apt install -y unzip make sbsigntool
wget https://gist.github.com/Snawoot/1937d5bc76d7b0a29f2039aa679c0449/raw/74a63c99be07ec93cfc1df47d2e98e54920c97b7/efitools-1.9.2-static.tar.xz && tar xpJf efitools-1.9.2-static.tar.xz -C /
wget https://github.com/Snawoot/linux-secureboot-kit/archive/master.zip
unzip master.zip
cd linux-secureboot-kit-master/
make debian9-install
Здесь все команды введены от имени суперпользователя. В итоге остаётся только убедиться, что Secure Boot включён в меню BIOS и защитить настройки BIOS паролем администратора.
А вот как выглядит попытка подмены рамдрайва на такой инсталляции:
Подмена загрузчика (внешний вид зависит от платформы):
Итог
Одного лишь дискового шифрования недостаточно для обеспечения конфиденциальности данных. Подпись всей цепи загрузки с использованием UEFI Secure Boot и GPG позволяет достичь хорошего уровня защиты от подмены исполняемого кода при условии, что эксплуатант компьютера способен распознать сброс или подмену системной платы, или даже всего компьютера. В противном случае крайне трудно предложить адекватные способы защиты, если пользователь готов ввести пароль/передать ключ в любую машину, которая случайно оказалась на столе или в серверной.
Комментарии (27)
Yaris
26.06.2019 13:46Я, может, чего-то упустил, но мне казалось, что FDE нужен ровно для одного сценария — ноут спёрли и пытаются что-то там где-то на диске расшифровать вдали от посторонних. В таком случае — удачи им.
Если же ноут побывал в чужих руках (особенно вне вашей области видимости) — это больше не ваш ноут. В лучшем случае от чужого любопытства спасёт полная переустановка, в худшем — продажа этого ноута и покупка нового.YourChief Автор
26.06.2019 19:37Да, всё верно, если известно, что техника скомпрометирована — остаётся только зачистить под ноль. Если полагаться только на это, то нужно заменять компьютер после похода на обед/в туалет более чем на полчаса; после сдачи в багаж в аэропорту; после потери питания в датацентре, если это сервер; после сдачи в сервис и так далее.
kay
26.06.2019 15:14Я проще сделал, у меня загрузчик с luks header'ом на флэшке. Но full chain, конечно, лучше.
armid
26.06.2019 18:51+1Я конечно не спец в шифрованиях, но выходит без этих танцев с security boot и загрузчиками, весь этот LUKS безтолку? Реально все так просто разшифровывается.
YourChief Автор
26.06.2019 19:03Если технику просто украдут, то шифрование поможет. Если незаметно такое провернут и владелец воспользуется компьютером — да, проблема. Secure Boot настроить не так трудно — пару раз в BIOS зайти и несколько команд прогнать.
Тут по сути ситуация похожа на фишинг паролей через сайты-подделки. Только по адресу сайта-подделки обычно видно, что это не тот сайт, а тут нет.ivlis
26.06.2019 22:54Так ещё надо настроить переподписывание ядра и initrd при обновлении, как-то организовать offline хранение корневого сертификата. И при любой ошибке иметь риск остаться без компьютера.
YourChief Автор
26.06.2019 23:04Решение в статье предусматривает переподписывание. Сертификат не представляет из себя особой ценности — при необходимости заходите в BIOS, вводите пароль администратора и сбрасываете платформу в режим установки. В статье этот момент оговорен.
ivlis
26.06.2019 22:49Если вы неуловимый Джо (в 99.99% так и есть) LUKS спасёт от очень любопытных глаз тех, кто может получить получить доступ к вашему компу/жесткому диску. Если кто-то собирается провести против вас операцию по подмене загрузочных файлов, то у вас уже неприятности.
dartraiden
26.06.2019 23:06+1без этих танцев с security boot и загрузчиками, весь этот LUKS безтолку?
Каждый из этих «танцев» защищает от своего сценария атаки.
1) Шифрование данных защищает от «воткнули любой LiveCD/воткнули диск в другой ПК, наплевали на авторизацию в системе и полезли смотреть содержимое диска». Это самое актуальное для большинства пользователей, поскольку накопитель можно потерять (вместе с ноутбуком), либо туда могут попытаться сунуть нос любопытные враги в погонах.
2) SecureBoot защищает от «в отсутствие владельца подменили его загрузчик GRUB на собранный злоумышленником кастомный GRUB, который логгирует введённый пароль и куда-то его сохраняет, чтобы потом можно было его заполучить» (атака EvilMaid). Если против вас такое организовали, то вы уже явно не рядовой пользователь.
3) Пароль на вход в настройки BIOS защищает от «зашли в биос, отключили SecureBoot и провернули п.2».
4) Использование TPM при шифровании защищает от «вытащили батарейку, сбросили пароль на биос, провернули п.3 и п.2» и от «прошили изменённую прошивку со встроенным UEFI-руткитом».
Безопасность — это комплекс мер. Например, использование лишь SecureBoot с собственными ключами защитит от подмены аагрузчика, но не защитит от банального «втыкаем диск в другую машину и смотрим содержимое».
Плюс ещё и разработчики операционных систем должны не зевать. Например, шины Thunderbolt и FireWire позволяют получить прямой доступ к оперативной памяти (откуда можно выудить ключ шифрования системного накопителя). Поэтому, разумно сделать так, чтобы устройства, вставленные при заблокированном сеансе (когда пользователь отошёл), не подключались. В Windows 10, например, это реализовано с помощью групповых политик, начиная с 1607 (а в 1803 добавили автоматически включаемую Kernel DMA Protection for Thunderbolt 3, правда, только при использовании процессоров Intel).
BiTHacK
26.06.2019 22:26Почему вы выбрали путь с отдельным загрузчиком, initramfs и т.д., а не шифрование /boot и установку подписанного загрузчика?
YourChief Автор
26.06.2019 23:27Главная причина — это было бы полумерой. Шифрование LUKS1 (LUKS2 c integrity GRUB не поддерживает) не гарантирует целостность данных. Действительно, подмену сформировать трудно, но не невозможно: см. слабые стороны XTS. Вместо этого я предпочёл иметь криптографические гарантии, что ядро подписано, конфиг GRUB подписан, инитрамдрайв подписан. О сомнительной пользе шифрования /boot я упоминал в статье.
В дополнение к этому такая схема легка во внедрении и сохраняет возможность воспользоваться оригинальным загрузчиком, отключив Secure Boot. То есть пользователь такого рецепта особо ничем не рискует, развёртывая это у себя на копьютере.BiTHacK
26.06.2019 23:39Ссылку на запрос на поддержку LUKS2 для GRUB оставлю здесь: savannah.gnu.org/bugs/?55093.
В случае btrfs подмена легко выявляется ввиду сохранения контрольных сумм файлов в ФС.rusbaron
27.06.2019 09:40Но разве подмена выяснится не после ввода пароля?
или сразу вывалится ошибка с несоответствием контрольных сумм?BiTHacK
27.06.2019 10:16При каждом монтировании проверяться все файлы не могут. Насколько мне известно, btrfs проверяет данные при их чтении. Для проверки всего диска можно использовать btrfs scrub start.
vit41ik
27.06.2019 10:05Ноутбуки как правило подключаются к сети Интернет через WiFi и соотвественно в момент загрузки ноутбука после ввода пароля к сети с помощью вашего скрипта ноутбук подключиться не сможет, если только не подключится к какой-либо открытой точки доступа без пароля(которых сейчас практически нет, используется авторизация через смс), а уже после загрузки самой системы ваши скрипты не будут работать. Получается, что ноутбуки уязвимы только если подключены к ethernet?
YourChief Автор
27.06.2019 10:14Нет, можно дождаться появления интернета для отправки пароля, спрятать ключ где-то на диске, добавить свой пароль на диск в кейслот LUKS, всё что угодно. Скрипты в моей демонстрации написаны для образовательных целей, а не для нужд практикующих злоумышленников.
pilniy
27.06.2019 11:50А спасет ли VeraCrypt?
YourChief Автор
27.06.2019 12:31Не пользовался им, но принципиальных отличий тут нет. Проблема не в самом способе шифрования, а в том, что можно вмешаться в работу компьютера до разблокировки и направить дальше действия компьютера в нужное для извлечения данных русло.
simplix
29.06.2019 11:25Как уже говорили выше, если техника побывала в чужих руках, её уже следует считать скомпрометированной. Все эти дополнительные защиты после чужих рук не особо помогут, так как векторов атаки можно придумать много, например:
- Встроить аппаратный кейлоггер между клавиатурой и устройством, позже забрать его или получить беспроводным методом. Это никак не определить без дополнительных мер защиты конкретно против такого способа получения пароля.
- Полностью подменить биос/чипсет и накопитель, чтобы процесс загрузки визуально соответствовал привычному. После ввода пароля не важно, что система не загрузится, пароль-то уже будет отправлен по сети. Даже если на биосе при включении стоит пароль, можно сделать так, чтобы он принимал любой пароль, всё равно никто не вводит сначала неправильный, чтобы убедиться в корректности алгоритмов.
dartraiden
И это лучше, чем ничего, поскольку колодка для подключения внешнего TPM даже на дешевых платах с топовым Z-чипсетом (например, ASUS Z170-P) в целях экономии не распаиваивается (хоть посалочное место есть, и то хорошо), а на самых бюджетных платах и того нет.
А как вы без сертификата Microsoft решаете проблему с запуском GOP-драйверов внешних видеокарт, PXE-драйверов внешних сетевых карточек, NVME-накопителей? Если с видеокартами ещё можно слить из них прошивку и подписать с помощью какого-нибудь GOPUpdater, то о существовании инструментов для NVME-дисков мне неизвестно.
YourChief Автор
Мне на ASUS B150M-C и на Dell Inspiron 3552 пришёл TPM 2.0 только с обновлением BIOS где-то в конце прошлого года. До этого TPM 1.2 просто никак не получалось завести на линуксе.
dartraiden
Как раз в конце 2018 для этой платы вышла новая мажорная версия прошивки (3xxx -> 4xxx). Интересно, с чем связано отсутствие до этого. На моей Z170-P поддержка PTT присутствует, как минимум, с 2016 года (более ранние прошивки я просто не проверял).
ivlis
С secure boot ещё не все опции ядра работают. Например на некоторых моделях Lenovo невозможно включить турборежим процессора из-за неверных таблиц acpi.
Ну мне всегда было как-то страшно брикнуть ноут, если что-то пойдёт не так с ключами.
dartraiden
Если что-то пойдет не так, у вас остаётся возможность зайти в настройки прошивки и восстановить ключи по умолчанию (если производитель не совсем отбитый и предусмотрел это).
Ну а если Linux убил прошивку (как уже бывало из-за рукожопости инженеров Lenovo), то уже всё равно, какие там были ключи, и такое убиение может случится вообще независимо от состояния Secure Boot.
YourChief Автор
Кстати, все рецепты, которые я привёл в статье (ссылка на рецепт для федоры и мой репозиторий) предусматривают резервное копирование ключей первым делом.