Étudiant en ce moment le chiffrement de disque sous linux, je propose un petit exercice pour s'en rendre compte. Sous linux, on utilise le frontend cryptsetup pour gérer la couche crypto:
# cryptsetup luksOpen /dev/sdb1 ciphered_sdb1
et la commande demande un mot de passe. S'il est correct, alors la clé maître de chiffrement du volume est libérée, permettant la lecture des données.La documentation précise que l'on peut passer ce mot de passe via un pipe | unix, comme par exemple:
# echo $MDP | cryptsetup luksOpen /dev/sdb1 ciphered_sdb1
ou bien
# cat randomfile | cryptsetup luksOpen /dev/sdb1 ciphered_sdb1
Imaginons donc un setup qui va extraire un certain nombre d'octets depuis /dev/random et qui va s'en servir comme clé de chiffrement.
Ce setup n'offre qu'une faible garantie contre une attaque bruteforce!
La raison en est simple et est précisée dans la fin du man cryptsetup. En effet, le passage de données via un pipe s'arrête dès le premier \n rencontré. Ce qui signifie que si dans les premiers caractères du fichier un \n est présent, alors la force de la clé est simplement équivalente au nombre de caractères précédent le \n! Démonstration:
Tout d'abord génération d'un fichier aléatoire tiré depuis /dev/random et utilisation de celui-ci pour formater une partition luks:
root@slack:~# dd if=/dev/random of=rnd bs=16 count=1
0+1 enregistrements lus
0+1 enregistrements écrits
16 octets (16 B) copiés, 0,00016936 s, 94,5 kB/s
root@slack:~# cat rnd | cryptsetup luksFormat /dev/loop0
root@slack:~# cat rnd | cryptsetup luksOpen /dev/loop0 ciphered
root@slack:~# cryptsetup luksClose /dev/mapper/ciphered
A première vue, le setup semble correct: tout d'abord, la clé est tirée depuis un générateur de hasard correct. Ensuite, la clé fait 16 octets ce qui est suffisant pour contrer les bruteforce. On a vérifié que tout fonctionne, le volume peut s'ouvrir si on dispose bien du fichier de clé.
Mais il se trouve que la force de la clé est beaucoup plus faible que 16 octets! (et dû également à un certain nombre d'essai successifs de ma part pour obtenir un rnd voulu :) )
root@slack:~# hexdump rnd
00000000 ca 41 71 0a 51 ba 56 55 f7 13 fb d9 94 0e 5c 2f
00000010
root@slack:~# printf '\xca\x41\x71' > loose00000000 ca 41 71 0a 51 ba 56 55 f7 13 fb d9 94 0e 5c 2f
00000010
root@slack:~# cat loose | cryptsetup luksOpen /dev/loop0 ciphered
root@slack:~# ls -l /dev/mapper/ciphered
lrwxrwxrwx 1 root root 7 août 23 21:19 /dev/mapper/ciphered -> ../dm-0
root@slack:~#
On constate que le fichier contient un 0a en 4e position, et que le volume s'ouvre uniquement avec la connaissance des trois précédents. Le système n'est donc absolument pas sécurisé malgré ce qu'il laissait imaginer puisqu'il est vulnérable à une attaque bruteforce. Pour éviter ce problème il faudrait s'assurer de ne jamais avoir de \n dans son fichier (ou d'utiliser l'option --key-file qui n'a pas ce problème, se référer à la page man partie: NOTES ON PASSWORD PROCESSING).
Comme indiqué en introduction il ne s'agit pas d'une attaque ou d'un scoop particulier, le but de cet article est simplement de montrer qu'un setup crypto qui fonctionne et qui paraît fiable ne l'est pas du tout.
...
RépondreSupprimercat rnd | tr -d '\n' | cryptsetup...
Mais il faut être particulièrement attentif à la documentation !
Que faudrait-il faire pour mitiger ce genre de vulnérabilités ? Audit régulier, lecture attentive de la doc, peut-être une levée d'alertes dans cryptsetup quand une clé faible est utilisée ?
Sinon cat rnd | base64 | cryptsetup
RépondreSupprimerPersonnellement, sans forcément avoir en tête ce type de problème, j'ai pris l'habitude de tout passer en base64.