Ce billet contient deux parties : la première explique succinctement les solutions/commandes pour pouvoir effacer toutes les données d’un disque (ou d’une partition). La deuxième approfondit les commandes et outils utilisés dans la première — Je me rend compte, après relecture du fait que j’ai pas mal dérivé dans l’écriture de cet article, il faut croire que j’avais beaucoup à dire.. donc si vous avez le temps, servez vous un café et profitez en bien.
MAJ Le 6 Mai 2009: Correction des fautes d’orthographe…
ATTENTION: Toutes les procédures ci-dessous sont définitives et non réversibles. Après avoir exécuté ces commandes, vous (ou un tiers) ne pourrez JAMAIS récupérer les informations qui y étaient stockées.
Info: Dans ce billet j’utiliserais comme chemin pour mon disque dur a effacer : /dev/sdX, il vous faudra naturellement le remplacer par le vôtre. Vérifiez toujours d’abord vôtre table de partition avec « df » (utilitaire sans risques, il permet simplement de lister les disques montés sur vôtre système – NDLR : fstab)
Suivant la distribution *nix que vous utiliserez vous ne pourrez sûrement pas directement réinitialiser le disque système : il vous faudra utiliser un « live CD » ou booter sur un autre disque dur.
1. L’utilitaire « dd »:
L’utilitaire « dd » fourni avec tous les *nix et dérivés, permet de faire de nombreuses manipulations sur des fichiers ou des systèmes de fichiers comme (liste non exhaustive): Formatter une disquette à partir d’une image, découper un fichier en plusieurs morceaux, faire une image d’un DVD ou encore — et c’est ce qui nous intéresse ici — détruire les données d’un disque dur en le remplissant de zéros ou de données aléatoires.
Il faut toujours faire attention lorsqu’on utilise dd. Le simple fait d’oublier une option ou d’échanger les arguments aura des conséquences désastreuses.
1.1 Méthode rapide et peu sûre :
La première méthode consiste à écrire des 0 sur tous les secteurs du disque en une seule passe :
dd if=/dev/zero of=/dev/sdX bs=512 conv=notrunc
L’argument « conv=notrunc » permet de ne pas limiter la taille du fichier de sortie.
1.2 Méthode lente et moyennement sûre :
La seconde méthode, un peu plus sûre que la précédente consiste en l’utilisation du périphérique générateur d’aléatoires du noyau. Ce qui aura pour effet d’écrire des données aléatoires sur tous les secteurs du disque :
dd if=/dev/urandom of=/dev/sdX bs=512 conv=notrunc
1.3 Méthode très lente et sûre:
Ici nous allons utiliser la première méthode, mais avec 32 passe.. De quoi vraiment tout effacer.
for n in `seq 32`; do dd if=/dev/zero of=/dev/sdX bs=512 conv=notrunc; done
Notez qu’ici j’ai défini le paramètre « BS » qui correspond au nombre d’octets spécifié écrit en une seule fois. Ce qui permet de raccourcir considérablement le temps de chaque passe.
1.4 Méthode vraiment très lente et très sûre:
Pour cette dernière solution, vous l’aurez déduit par vous même, 16 passes de random, de quoi effacer définitivement n’importe quel octet sensible ! Suivant la taille du disque/partition, cette solution peut prendre énormément de temps…
for n in `seq 16`; do dd if=/dev/urandom of=/dev/sdX bs=512 conv=notrunc; done
Approfondissements :
Temps des opérations — Optimisations
Voyons comment se comporte dd pour un fichier test de 100Mb avec notre solution n°1 et un Block size de 1:
$ time dd if=/dev/zero of=/tmp/zero bs=1 conv=notrunc count=102400000
102400000+0 records in
102400000+0 records out
102400000 bytes transferred in 458.989378 secs (223099 bytes/sec)
real 7m38.997s
user 1m52.333s
sys 5m30.299s
1 * 102400000 = 100Mb, dd a mis environ 7 minutes 38 secondes, pitoyable, pourquoi ?!
Petites précisions indispensables au sujet des secteurs (ou blocs):
Un secteur (ou bloc) est une subdivision d’une piste de votre disque dur. Chaque secteur peut stocker un nombre bien défini de données — les disques magnétiques fournissent généralement un espace de 512 octets (ce n’est pas le cas des SSD). La notion de bloc a été utilisée au début de l’informatique pour ce petit morceau de données, mais le terme secteur est devenu beaucoup plus courant. Puis peu à peu, « bloc » est devenu plus employé pour définir un certain nombre de données (variable) utilisé par un processus. Par exemple, le programme dd qui permet de définir la taille de bloc à utiliser lors de l’exécution avec le paramètre BS (= octets). En réalité, ça ne change pas la taille du secteur d’un support, seule la taille des données qui seront manipulées.
Notez que pour un CD, la taille d’un secteur est de 2.048 bytes (par exemple, si vous avez besoin de créer une image iso, tapez : dd if=/dev/hdc of=/tmp/mycd.iso bs=2048 conv=notrunc).
Reprenons — comment puis-je vérifier la taille des blocs sur un BSD ?
$ pdisk /dev/rdisk1 -blockSize
512
Et sur un Linux ?
tune2fs -l /dev/md1 | grep Block
Block count: 5118688
Block size: 4096
Blocks per group: 32768
Notez que sur le deuxième exemple, le système de fichier est en fait monté sur un RAID, d’où la réponse de BS de 4k.
Bien, maintenant que nous savons, essayons en spécifiant un BS de 512:
$ time dd if=/dev/zero of=/tmp/zero bs=512 conv=notrunc count=200000
200000+0 records in
200000+0 records out
102400000 bytes transferred in 1.615840 secs (63372613 bytes/sec)
real 0m1.618s
user 0m0.240s
sys 0m1.015s
512 * 200000 = 100Mb, dd a mis à peine plus d’une 2,4s (contre 7m38) — la différence est énorme, pourquoi ?
En fait, l’explication est simple, c’est la synchronisation entre les données envoyées et les données écrites. Des blocs de 512 octets sont envoyés au disque et sont directement écrits sur les secteurs correspondants ; inutile de mettre en cache 512 fois 1 octet pour pouvoir écrire notre bloc. Et si on spécifie un BS supérieur, me direz-vous ? Essayons.
time dd if=/dev/zero of=/tmp/zero bs=1024 conv=notrunc count=100000
100000+0 records in
100000+0 records out
102400000 bytes transferred in 3.185333 secs (32147345 bytes/sec)
real 0m3.188s
user 0m0.131s
sys 0m0.693s
En effet, cela ne nous apporte rien ! notez que j’ai spécifié bs=512, mais en fait dd utilise par défaut le block size de 512.
/dev/zero, /dev/random ou /dev/urandom ?
Pour cette partie, je me suis largement inspiré des manpages de random que j’ai agrémentée d’exemples et quelques précisions.
Les fichiers spéciaux /dev/random et /dev/urandom existents depuis Linux 1.3.30 et ils fournissent une interface avec le générateur de nombres aléatoires du noyau. Il faut savoir que le noyau identifie chaque périphérique au moyen de deux numéros, le majeur (à gauche) et le mineur (à droite), ex:
ls -l /dev
crw-rw-rw- 1 root root 1, 5 avr 29 14:07 zero
crw-rw-rw- 1 root root 1, 8 avr 29 14:07 random
crw-rw-rw- 1 root root 1, 9 avr 29 14:07 urandom
Le fichier /dev/random a un numéro de périphérique majeur égal à 1, et un numéro mineur égal à 8. Les numéros du périphérique /dev/urandom sont 1 pour le majeur, et 9 pour le mineur et pour zero ils sont respectivement de 1 et 5. Ils sont de type c (Character), ils communiquent octet par octet (comme un port série) à l’inverse des disques durs qui sont de type b (Blocks) et qui – donc – communiquent par blocs de données.
Ce que l’on peut lire dans la documentation de noyau Linux a leurs propos :
1 char Memory device
...
5 = /dev/zero Null byte source
...
8 = /dev/random Nondeterministic random number gen.
9 = /dev/urandom Faster, less secure random number gen.
...
En réalité, le générateur de nombres aléatoires récupère les séquences aléatoires en fonction du « bruit » généré par l’environnement : mouvement de la souris, frappe au clavier, etc.. Le générateur mémorise également une estimation du nombre de bits de bruit dans son réservoir d’entropie, et utilise son contenu pour créer des nombres aléatoires.
En effet, lors d’une lecture, le périphérique /dev/random sera limité au nombre de bits de bruit qu’il contient.
/dev/random est particulièrement adapté pour des cas où l’on a ponctuellement besoin de nombres hautement aléatoires (création de clés par exemple). Lorsque le réservoir d’entropie est vide, les lectures du périphérique /dev/random seront bloquantes jusqu’à l’obtention de suffisamment de bruits en provenance de l’environnement. Dans notre cas – ou l’on a besoin d’une très grande quantité de données —, nous risquons d’être très rapidement limité ! Heureusement, /dev/urandom renverra autant d’octets qu’on en demande. Toutefois, s’il n’y a plus assez de bits disponibles dans le réservoir d’entropie, les valeurs renvoyées pourraient être théoriquement vulnérables à une cryptanalyse basée sur l’algorithme employé par le pilote. Il n’existe pas de documentation sur ce type d’attaque dans la littérature publique actuelle, mais cela n’élimine pas le risque théorique.
Le fichier de périphérique /dev/zero quand a lui, se comporte comme s’il contenait une infinité d’octets à ~0. Quelle que soit la quantité de données que vous essayez de lire à partir de /dev/zero, il générera suffisamment d’octets nuls.
$ hexdump /dev/zero
0000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
$ hexdump -C /dev/random
00000000 c8 6a 22 ab 8a cb a2 66 17 7a ce 8d d6 e8 e1 fa |?j"?.ˢf.z?.????|
00000010 c1 69 7c d1 64 39 44 cc be 8f 06 db 88 1e 5c ba |?i|?d9D̾..?..\?|
00000020 99 9d a3 f7 cb ff a4 ea 43 c1 b4 ea b8 ba f9 71 |..??????C??긺?q|
...
$ hexdump -C /dev/urandom
00000000 49 db 3d 9e 25 bf 14 b9 b8 a6 58 22 b1 13 7b 29 |I?=.%?.???X"?.{)|
00000010 33 40 bf 14 e5 aa 99 c9 a0 ee fb 5c 74 5a 01 d6 |3@?.?.ɠ??\tZ.?|
00000020 6b 45 33 6c a4 d6 69 54 53 d8 17 55 ba dc 8c 76 |kE3l??iTS?.U??.v|
...
En résumé, nous allons plutôt utiliser /dev/urandom ou /dev/zero, sinon ça va prendre un temps fou. /dev/random donne de l’entropie « forte » (liée au matériel) et ne donne donc que quelques octets par seconde. /dev/urandom complète cette entropie forte avec du PRNG et génère donc les données aussi vite que nécessaire, ou presque..
Dans le cas d’un effacement de disque dur, ce risque nous importe peu, mais je trouvais intéressant d’en parler.
Petites précisions pour les BSD Users:
1) Le générateur de bruit random a été remplacé par un générateur cryptographique nommé « Yarrow algorithm » ;
2) /dev/urandom est un lien symbolique sur /dev/random.
3) Les numéros mineurs et majeurs ne sont pas les mêmes, ex:
$ ls -l /dev | grep random
crw-rw-rw- 1 root wheel 8, 0 5 mai 15:23 random
crw-rw-rw- 1 root wheel 8, 1 3 mai 15:52 urandom
Vérifications
Pour vérifier l’oeuvre de la commande dd couplée à random, nous allons utiliser « hexdump » (sur un fichier de 64b, pour une question de lisibilité).
Utilisons « zero » comme générateur:
$ dd if=/dev/zero of=/tmp/zero count=1 bs=64 && dd if=/tmp/zero | hexdump -C | grep [^00]
1+0 records in
1+0 records out
64 bytes transferred in 0.000035 secs (1826092 bytes/sec)
0+1 records in
0+1 records out
64 bytes transferred in 0.000018 secs (3532045 bytes/sec)
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000040
Quand à utiliser « random », voici le résultat :
dd if=/dev/random of=/tmp/zero count=1 bs=64 && dd if=/tmp/zero | hexdump -C
1+0 records in
1+0 records out
64 bytes transferred in 0.000040 secs (1597830 bytes/sec)
0+1 records in
0+1 records out
64 bytes transferred in 0.000016 secs (4006499 bytes/sec)
00000000 68 0f 9a a5 f8 9c 1a 45 fa ce c2 04 64 0d 3a a2 |h..??..E???.d.:?|
00000010 d5 59 f1 10 05 4a cc b0 ec 69 3a 26 f6 f9 42 c3 |?Y?..J̰?i:&??B?|
00000020 28 81 32 7b 3e f5 7c 3a a8 d9 75 63 bd 16 21 8e |(.2{>?|:??uc?.!.|
00000030 9a 9e 28 43 bc 69 3c 7a 53 11 8b 9b 7c 8d 86 2e |..(C?i
Vous pourrez, naturellement vérifier le résultat en situation « réelle » grace a la commande suivante :
dd if=/dev/sdX | hexdump -C | grep [^00]
Note finale
Il existe des logiciels comme "Shred" qui offrent des solutions « clés en main », mais qui au final ne font que ce que vous auriez très bien pu faire avec "dd" (un nombre X de passes random puis finir sur une "zero"), ex:
Les deux lignes suivantes font la même chose:
shred -fzv -n 16 /dev/sdX
for n in `seq 15`; do dd if=/dev/urandom of=/dev/sdX conv=notrunc; done; dd if=/dev/zero of=/dev/sdX conv=notrunc
sachant que - pour un disque de 500Go - dd a été le plus rapide chez moi.
Il existe un ensemble d’outils nommé « secure_deletion toolkit », mais il n'est pas encore porté sur toutes les plates-formes. Par exemple, l'outil « sfill » pousse l'effacement sécurisé des fichiers à son paroxysme :
* Une passe avec 0xff
* 5 passes aléatoires avec la source /dev/urandom
* 27 passes avec des valeurs spéciales définies par Peter Gutmann. (Je vous invite d'ailleurs a lire son article très complet si vous voulez en savoir plus.)
* A nouveau 5 passes aléatoires.
* Une passe avec 0x00.
Il est peu être possible de lire « à côté des pistes », des résidus magnétisés et de retrouver ainsi des données écrites préalablement en décalant les têtes et peut être existe'il d'autres méthodes dont nous n'avons pas connaissance alors il reste une solution universelle et radicale : La destruction physique. C'est la seule solution réellement viable et irrécupérable : Perceuse, Masse, Acide et j'en passe..
Le générateur random et l'utilitaire dd sont disponibles sur énormément de distributions : Solaris, Mac OS X, FreeBSD, HP-UX, Tru64, AIX et j'en passe.
Possibly Related Posts:
- Du load-balancing avec vyatta
- Got error 28 from storage engine query: SELECT * FROM …
- Crashdump.fr passe en AES-256.
- ARP Spoofing (ARP Cache poisoning)
- HackThisSite.org Basic Howto: 1 à 10












Guiguiabloc says:
Ah sympa l’article :-)
J’ai failli perdre ma collection de pr0n avec tes essais :-p
Sinon, pour la génération de nombre aléatoires, il existe le joli paquet rng-tools (nécessite bien évidemment la carte qui va bien, mais on peut tout aussi bien lui passer un HRNGDEVICE=/dev/random ou /dev/urandom si on manque un peu d’entropie, fréquent sur un serveur sans clavier/souris ;-) )
mai 05, 2009, 8:26Adri says:
si tu veux je rsync ta collection pour la mettre en sécurité :p
mai 05, 2009, 11:23je n’avais pas du tout pensé a rng-tools.. il va falloir que je rajoute une touche a ce billet, merci :)
Vanessa says:
Super intéressant !!
mai 05, 2009, 17:03(PS: si tu pouvais justifier le texte ça nous faciliterait la lecture !!)
Adri says:
Merci, promis je m’occupe de ça des que je suis de retour chez moi-
mai 05, 2009, 23:46