Hackear e proteger unidades de criptografia LUKS


A criptografia de disco foi projetada para proteger os dados no seu computador contra acesso físico não autorizado. Há um equívoco comum de que a criptografia de disco realmente lida com essa tarefa, e cenários nos quais isso não é tão exótico e irrealista. Este artigo mostra que a extração da chave mestra de um volume LUKS criptografado é facilmente viável na prática e é proposto um método de proteção (há muito tempo).

A essência do problema


Também devemos insistir no objetivo da criptografia de disco. De fato, quando o acesso físico é impossível e o sistema em execução é o proprietário dos dados, não há problemas. Pode haver problemas com a segurança do próprio sistema, mas a criptografia de disco não ajudará aqui. A criptografia de disco deve proteger os dados quando uma parte curiosa tiver a oportunidade de acessar discos sem passar pelo sistema, por exemplo, conectar fisicamente os discos ao sistema ou carregar o SO em um computador inspecionado. Um cenário de acesso físico é o único cenário em que a criptografia de disco faz algum sentido.

O problema é que o invasor pode intervir silenciosamente na cadeia de inicialização do SO e forçar o sistema a emitir chaves de criptografia assim que as receber na próxima vez em que for iniciado.

Tal ataque requer apenas um ato de acesso ao computador: os dados do disco podem ser copiados juntamente com a substituição do circuito de inicialização e depois descriptografados por eles até que a chave apareça. Comparado aos discos não criptografados, o único inconveniente é que você precisa cuidar de como a chave é transmitida e aguardar o início.

Em seguida, passamos a demonstrar essa técnica na prática. Pode acontecer que, para sua implementação, o invasor precise de menos esforço do que o proprietário do sistema gastou na configuração de alguns de seus métodos exóticos de desbloqueio de discos (por exemplo, remotamente).

Demonstração prática


Conduzirei uma demonstração no exemplo de uma máquina virtual com o Debian 9, na qual a criptografia de disco foi ativada durante a instalação do sistema.

A instalação do Debian 9 com criptografia cria uma partição de inicialização e uma partição com LVM criptografado. Captura de tela do sistema instalado solicitando a senha de descriptografia para maior clareza:



Tudo está pronto, você pode prosseguir. Desligue o carro, copie o disco. No meu caso, fica assim:

 [root @ dt1 ~] # virsh destrói o debian9-boothack 
 O domínio debian9-boothack é destruído

 [root @ dt1 ~] # cp -v /var/lib/libvirt/images/debian9-boothack.qcow2 ~
 '/var/lib/libvirt/images/debian9-boothack.qcow2' -> '/root/debian9-boothack.qcow2'


Monte a unidade da máquina, extraia o initramdrive:

 [root @ dt1 ~] # mkdir / convidado
 [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'


Descompacte o initramdrive:

 [user @ dt1 tmp] $ mkdir descompactado
 [user @ dt1 tmp] $ cd descompactado /
 [user @ dt1 descompactado] $ zcat ../initrd.img-4.9.0-9-amd64 |  cpio -idm
 [user @ dt1 descompactado] $ ls
 bin conf etc init lib lib64 executa scripts sbin

Feito, você pode editar o initramdrive. Sabendo que a máquina possui uma conexão de rede permanente, desejo organizar o envio criptografado da chave mestre depois de abrir os discos. Para fazer isso, precisarei de:

  1. Utilitário para envio criptografado pela rede . Adicione-o ao /sbin
  2. Script de shell para extração e envio de chaves . Enviado para /scripts/local-top e adicionado à lista /scripts/local-top/ORDER após cryptoroot .
  3. O script de processamento de eventos udhcpc nativo ausente para iniciar o ajuste automático da rede diretamente no ramdrive, usando as ferramentas internas . Seu lugar de direito é em /etc/udhcpc/default.script

O executável secsend é construído estaticamente para eliminar dependências em qualquer biblioteca. Sob condições normais, o assembly produz um arquivo de saída de 2,7 MB, o que é bastante perceptível em comparação com o tamanho da ramdrive - 62 megabytes na forma descompactada e 20 na compactada. No entanto, ao criar todas as bibliotecas e o executável com o mínimo de libl musl, o tamanho do arquivo de saída é de ~ 250 KB e 120 KB após a compactação UPX. O próprio Secsend simplesmente lê a entrada padrão, criptografa-a com cryptobox da libsodium usando a chave pública especificada Curve25519 e envia dados para o endereço especificado via TCP. Seu uso não tem princípios para o objetivo principal da demonstração, mas mostra que o invasor é essencialmente ilimitado: você pode executar um código que faça o que o invasor deseja e como ele deseja.

Depois de adicionar esses três arquivos e editar outro, você pode compactar tudo e devolver o arquivo modificado ao seu lugar:

 [user @ dt1 descompactado] $ find.  |  cpio -o -c |  gzip -9> ../initrd.img-4.9.0-9-amd64
 125736 blocos
 [user @ dt1 descompactado] $ 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 descompactado] $ sudo guestunmount / guest

Vai demorar algum servidor para receber uma chave mestra criptografada, como esta (Python 3.5.3+). Ao iniciá-lo com a parte secreta do par de chaves, esperamos até que a vítima condicional ligue o computador:



Quando você liga uma máquina virtual com um disco criptografado, tudo parece normal, nada mudou:



Mas no lado do ouvinte de conexão, uma chave mestra secreta apareceu:



A partir desse momento, a máquina virtual com dados e seu usuário com conhecimento da senha de criptografia não interessam mais ao invasor. Enfatizo que alterar uma senha não altera a chave mestra com a qual todo o volume é criptografado. Mesmo que de alguma forma uma alteração da senha tenha ocorrido entre copiar e enviar a chave, isso não é um obstáculo. Usaremos a chave mestra para abrir o volume. Para fazer isso, convertemos sua entrada de log de 16 casas decimais em um arquivo binário:

 [root @ dt1 ~] # echo 'fa0c53 *********** 4 ediçõesc' |  xxd -r -p> master.key

Monte discos com uma cópia:

 [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 ~] # arquivo -s / dev / nbd0p5
 / dev / nbd0p5: arquivo criptografado LUKS, versão 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
   Atributo PV VG Fmt 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% Log de Movimentos 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 perdido + encontrado mídia mnt opt ​​proc root executar sbin srv sys tmp usr var vmlinuz vmlinuz.old
 [root @ dt1 ~] # cat / raiz hackeada / etc / nome do host 
 debian9-boothack

Os dados são recuperados.

Medidas de proteção


Como você pode concluir, a raiz do problema é o lançamento de código não confiável. Aqui está uma breve visão geral das técnicas que devem ser consideradas no contexto deste problema.

Criptografia de partição de inicialização


Algumas distribuições também oferecem esse recurso durante a instalação (por exemplo, OpenSuSE). Nesse caso, a partição de inicialização é descriptografada pelo carregador de inicialização e, em seguida, o kernel e o initramdrive são carregados a partir dela. Essa abordagem não faz muito sentido pelos seguintes motivos:

  • O problema mais importante da falsificação de código ainda permanece em aberto. Somente agora o carregador de inicialização precisará ser substituído.
  • Para uma partição de inicialização, a integridade dos dados não é mais importante, mas a integridade dos dados. A criptografia básica LUKS não fornece essa garantia. Alguns benefícios aqui residem apenas no fato de que é difícil formar uma substituição significativa em uma partição criptografada.
  • A criptografia LUKS2 com verificação de integridade (integridade dm) também não protege contra interferências, porque não oferece garantias contra ataques relacionados à reprodução do setor. Por exemplo, tendo um despejo dessa partição e uma configuração do carregador de inicialização nela, você ainda pode recuperar e reverter o kernel para o estado copiado anteriormente. Isso não oferece vantagens especificamente na questão da extração de chave (exceto se o kernel antigo estava vulnerável e pode ser usado de alguma maneira), é um argumento a favor da inutilidade de criptografar a partição de inicialização.

Usando o TPM para armazenar uma chave de criptografia e validar um ambiente de inicialização seguro


O TPM é essencialmente um processador de criptografia que atua como um enclave seguro ou cartão inteligente no sistema. Os dados secretos criptografados com ele só podem ser descriptografados usando-o e apenas em suas condições - quando os valores de PCR do sistema convergem, que dependem do estado da plataforma e do código executado nele. A tecnologia é bastante promissora e pode permitir que você implemente criptografia segura no sistema sem exigir uma chave (por exemplo, inserindo com uma impressão digital ou métodos de autenticação não relacionados à criptografia). Idealmente, ele deve funcionar em conjunto com o UEFI Secure Boot, proibindo a descriptografia quando a configuração não convergir.

No entanto, no Linux, o suporte ao TPM ainda está engatinhando. O carregador de inicialização TrustedGRUB2 (um carregador de inicialização adaptado para trabalhar com o TPM) não suporta UEFI e o ponto principal da ideia desaparece disso. Além disso, a presença de um TPM 2.0 funcional só agora começa a aparecer no hardware, geralmente junto com as atualizações do BIOS. A maioria das placas-mãe não possui um módulo TPM discreto; em vez disso, o TPM é um software implementado no Intel ME . Por todos esses motivos, ainda não considero essa configuração como adequada e adequada para uso generalizado.

Usando o UEFI Secure Boot para cobrir completamente a cadeia de inicialização com uma assinatura eletrônica


Existem distribuições (Fedora, OpenSuSE) e soluções únicas que permitem usar o Secure Boot no Linux. No entanto, as soluções in a box geralmente não fornecem integridade de código na cadeia de carga. Eles foram projetados principalmente para garantir que o Linux simplesmente inicie quando o Secure Boot estiver ativado. Normalmente, apenas usa o shim EFI, assinado por um certificado da Microsoft, que executa qualquer coisa. Portanto, ao usar a certificação externa, é simplesmente impossível cobrir a assinatura de uma unidade em disco gerada diretamente no sistema instalado.

Existem artigos no hub que sugerem o uso de sua própria PKI para assinar o código. Isso permite que você assine tudo o que precisa por si mesmo e, assim, cubra toda a cadeia UEFI → gerenciador de inicialização → kernel e intramdrive.

  1. Domando UEFI SecureBoot - o primeiro artigo sobre o hub sobre este tópico, muito detalhado.
  2. Usamos o Secure Boot no Linux ao máximo - é especialmente bem escrito aqui por que o Secure Boot com certificados da Microsoft instalados é equivalente a sua ausência.

O resultado requerido é obtido no segundo artigo. Uma assinatura intramdrive é obtida mesclando o ramdrive e o kernel em um aplicativo EFI, sem usar um carregador, e o UEFI verifica diretamente a assinatura imediatamente em massa. Ambos os manuais exigem muito trabalho manual em cada sistema protegido.

Solução Acessível


Eu criei uma abordagem para a implementação completa do Secure Boot, compatível com o esquema de inicialização geralmente aceito e sem exigir intervenção séria no sistema: um gerenciador de inicialização separado, um ramdrive separado, um kernel separado. O UEFI verifica apenas a assinatura do carregador de inicialização GRUB2, o carregador de inicialização possui uma configuração com fio com a chave para verificar a assinatura e a senha do administrador e, em seguida, verifica o kernel e o ramdrive. O carregador de inicialização assinado é instalado em paralelo com o antigo e, se necessário, continua sendo possível iniciar da maneira usual, desativando o Secure Boot. Obviamente, esse recurso deve ser fechado pela senha de administrador no menu de configurações UEFI.

Decidi automatizar o processo de implantação do Secure Boot com minha própria PKI e torná-lo o mais simples e independente de distribuição possível. O resultado é exatamente esse conjunto da receita e utilitários do Makefile: https://github.com/Snawoot/linux-secureboot-kit . Para debian, ubuntu, fedora e centos, todo o processo requer apenas alguns comandos.

Especificamente, com o exemplo do Debian 9, a instalação se parece com isso (assumindo que o UEFI já esteja no modo de configuração):

 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 

Aqui, todos os comandos são inseridos em nome do superusuário. Como resultado, resta apenas verificar se a Inicialização segura está ativada no menu do BIOS e proteger as configurações do BIOS com uma senha de administrador.

E aqui está a tentativa de substituir o ramdrive nessa instalação:



Substituição do carregador de inicialização (a aparência depende da plataforma):



Sumário


A criptografia de disco sozinha não é suficiente para garantir a privacidade dos dados. A assinatura de toda a cadeia de inicialização usando o UEFI Secure Boot e o GPG permite alcançar um bom nível de proteção contra falsificação de código executável, desde que o operador do computador possa reconhecer uma redefinição ou falsificação da placa do sistema ou mesmo de todo o computador. Caso contrário, é extremamente difícil oferecer métodos de proteção adequados se o usuário estiver pronto para inserir a senha / transferir a chave para qualquer máquina que acidentalmente termine na mesa ou na sala do servidor.

Source: https://habr.com/ru/post/pt457542/


All Articles