File: nielsen2.html

package info (click to toggle)
lg-issue63 1-5
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,616 kB
  • ctags: 99
  • sloc: perl: 201; makefile: 36; python: 36; sh: 4
file content (467 lines) | stat: -rw-r--r-- 18,448 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
<!--startcut  ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Securely Erasing a Hard Drive with Perl LG #63</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->

<CENTER>
<A HREF="http://www.linuxgazette.com/">
<H1><IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png" 
	WIDTH="600" HEIGHT="124" border="0"></H1></A> 

<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="nielsen.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="lg_toc63.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_frontpage.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue63/nielsen2.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom"  ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="nielsen3.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom"  ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<P>
</CENTER>

<!--endcut ============================================================-->

<H4 ALIGN="center">
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>

<P> <HR> <P> 
<!--===================================================================-->

<center>
<H1><font color="maroon">Securely Erasing a Hard Drive with Perl</font></H1>
<H4>By <a href="mailto:articles@gnujobs.com">Mark Nielsen</a></H4>
</center>
<P> <HR> <P>  

<!-- END header -->




<H3>Contents</H3>

<ol>

<li>
<a href="#Introduction">Introduction</a></li>
<li>
<a href="#problems">What problems I have.</a></li>

<li>
<a href="#perl">The Perl Script</a></li>

<li>
<a href="#Conclusion">Conclusion</a></li>

<li>
<a href="#REF">References</a></li>
</ol>

<h3>
<a NAME="Introduction"></a>Introduction</h3>
When moving from Ohio to California, GNUJobs.com had some hard drives
(along with other hardware and software)
which were to be donated to 
<a href="http://www.colug.net">COLUG</a> (Central Ohio Linux Users Group). 
They needed to be deleted
before they were donated. 
2 out of the 3 hard drives had bad sectors on them, and the third
I ended up using as a hard drive for testing purposes, like creating
this article, so I ended up not giving any away. Still, I will need to
wipe a hard drive in the future, so I created this Perl script (which I 
will later convert to Python and make it have more options).
<p>
The goal of this Perl script is to just delete the hard drive at /dev/hdb 
(the slave drive on the Primary IDE controller) since I have a hard drive
removeable kit there. I want it to delete all partitions, create one
partition that takes up the whole hard drive, and then fill up the
hard drive with garbage data (including some random encrypted data
just to ruin a hacker's day trying to find out what the data is).      

<h3>
<a NAME="problems"></a>The Problems</h3>

Here is a list of problems I had and how I solved them:
<ol>
<li> <font size= +1>How do I get it to delete all the partitions?</font>
<p>I remember researching many different options to alter partitions on 
a hard drive, and doing it manually yielded the best results. I had used
a Perl Expect script to automate the fdisk program (fdisk partitions hard 
drives in Linux) in the past, and I decided to continue to do it
that way. I believe
there are better alternatives for the simple task of deleting all the 
partitions, like sfdisk and others, but if one solution covers all 
possibilities with 100% power and flexibility, I usually just stick to
one way of doing things so that I don't have to remember too many things
and if it ever gets more complicated, I don't have to learn anything new.  

<p>Thus, I used Expect code to simulate a user typing in the commands
for fdisk. The Expect code deleted all the partitions and then
it created one big partition.<p></li>
<li><font size=+1>How do I fill up the hard drive with garbage data?</font> 
<p> Just deleting partitions isn't enough to delete the data. I want 
to overwrite all old data 
with garbage to make sure the previous data was deleted.
I used sfdisk to get the size of the partition that fdisk created.
Then, I created a loop which would continuously print garbage data 
until the amount printed was equal or greater than the size of the partition.
<p></li>
<li>
<font size=+1> How do I put binary data on the hard
 drive to confuse a hacker?</font> 
 <P> I created random binary data using the
random function and "chr" function in Perl. Then, I encrypted the random
data using the Perl Blowfish module. If someone manages to decrypt the
data, it will still look like garbage and confuse them. I wanted to encrypt
the data so that it didn't look purely random in a mathematical sense.
<p> </li>
<li> <font size=+1> How do I reformat the big partition?</font> 
 <P> This was easy.  I just used a simple "mkfs" command. 
</ol>

<h3>
<a NAME="perl"></a>The Perl Script</h3>
The version of Perl I was using for this Perl script was out of date. 
I was using Perl 5.005_03 and I believe Perl is up to 5.6 as of 1/2001.
<p>
There are a lot of things I need to enhance to make this 
script more user friendly. There should be a lot more error checking,
considering how dangerous this script is, and prompts to ask a user
if they really want to do so stuff. I am waiting until I restart my MILAS
project (which will be written in Python) before I make this script better.
It was only to get me through moving from Columbus to the Bay Area.   
<p> I have commented a lot of the code, so hopefully a novice Perl
programmer can understand most of what I am trying to do.   

<A HREF="misc/nielsen2/Wipe_It.pl.txt">(Text version of this listing)</A>

<pre>
#!/usr/bin/perl

##### Things to do
# 1. Make sure we create a brand new directory for temporary mounting
#     in order to avoid security risks in case someone is logged in.
# 2. Use perl functions to handle a lot of the system calls. 
# 3. Let it autodetect hard drives, and floppy drives, and only perform
#    actions on unmounted hard drives and floppy drives.
##### 

use strict;
use Expect;
use Crypt::Blowfish;

#-----------------------------------------------
my $Junk;
  ### Set the drive to the slave drive on the Primary IDE controller.
my $Drive = "hdb";

  ### Let us do a lot of random stuff, and get the last line from the
  ### /etc/passwd file to make it really random, assuming one person
  ### has been added to the computer. 
my $time = time();
my $Ran = rand($time);
my $Ran = rand(10000000000000);
my $LastLine = `tail -n 1 /etc/passwd`; chomp $LastLine;
$LastLine = substr ($LastLine,0,30);
my $Blowfish_Key = $LastLine . $Ran . $time;
$Blowfish_Key = substr ($Blowfish_Key,0,20);
while (length ($Blowfish_Key) &lt; 56) 
  {
  $Blowfish_Key .= $Ran = rand($time);
  }
$Blowfish_Key = substr ($Blowfish_Key,0,56);

  ### Done making up random key, now create Blowfish Encryption object.
my $Blowfish_Cipher = new Crypt::Blowfish $Blowfish_Key;

#------------------------------------
system "clear";
print "This will wipe out the hard drive on Drive /dev/$Drive\n";
print "Press enter to continue\n";
my $R = &lt;STDIN&gt;;

  ### Get the list of mounted partitions on the drive we want to wipe out
my @Mounted = `df`;
@Mounted = grep($_ =~ /\/dev\/hdb/, @Mounted);
  ### Foreach mounted partition, umount it
foreach my $Mount (@Mounted)
  {
  my ($Partition,$Junk) = split(/\s+/, $Mount,2);
  print "Unmounting $Partition\n";
  my $Result = system ("umount $Partition");
  if ($Result &gt; 0) 
    {
    print "ERROR, unable to umount $Partition, aborting Script, Error = $Result\n";
    exit;
    }
  }

  ### Start the expect script, which will simulate someone doing this
  ### commands manually.
my $Fdisk = Expect-&gt;spawn("/sbin/fdisk /dev/$Drive");

  ### Get a list of mounted partitions by printing the partition table 
print $Fdisk "p\n";
my $match=$Fdisk-&gt;expect(30,"Device Boot    Start");

my $Temp = $Fdisk-&gt;exp_after();
my @Temp = split(/\n/, $Temp);
  ## Get the lines that tell us about the partitions
my @Partitions = grep($_ =~ /^\/dev\//, @Temp);

  ## Foreach line, delete the partition
foreach my $Line (reverse @Partitions)
  {
    ## Get the /dev/hdb part, and its number
  my ($Part,$Junk) = split(/[\t ]/, $Line,2);
  my $No = $Part;
  $No =~ s/^\/dev\/$Drive//;

  print "Deleting no $Drive $No\n";     

    ## Delete command
  print $Fdisk "d\n";    
  $match=$Fdisk-&gt;expect(30,"Partition number");
   
    ## Which partition number to delete
  print $Fdisk "$No\n";
  $match=$Fdisk-&gt;expect(30,"Command (m for help):");
  }

$Fdisk-&gt;clear_accum();

  ### If we had partitions, write changes, or otherwise, just end it
if (@Partitions &lt; 1) {print $Fdisk "q\n"; $Fdisk-&gt;expect(2,":");}
else 
  {
  print $Fdisk "w\n";
  $Fdisk-&gt;expect(30,"Command (m for help):");
  }

#-------------------------------
  ## Get the geometry of the hard drive
my $Geometry = `/sbin/sfdisk -g /dev/$Drive`;
my ($Junk, $Cyl, $Junk2, $Head, $Junk3, $Sector,@Junk) = split(/\s+/,$Geometry);
if ($Cyl &lt; 1) 
   {print "ERROR: Unable to figure out cylinders for drive. aborting\n"; exit;}

  ### Create a new expect script to simulate a person using fdisk
my $Fdisk = Expect-&gt;spawn("/sbin/fdisk /dev/$Drive");

   #### Tell fdisk to create new partition
print $Fdisk "n\n";
$Fdisk-&gt;expect(5,"primary");

  ### Tell it the new partition should be a primary partition
print $Fdisk "p\n";
$Fdisk-&gt;expect(5,":");

  ### Which partition, number 1
print $Fdisk "1\n";
$Fdisk-&gt;expect(5,":");

  ### Start at cylinder 1
print $Fdisk "1\n";
$Fdisk-&gt;expect(5,":");

  ### Go to the end
print $Fdisk "$Cyl\n";
$Fdisk-&gt;expect(5,":");

  ### Write and save
print $Fdisk "w\n"; 
$Fdisk-&gt;expect(30,"Command (m for help):");

#------------------------------------------
### Format the partition and mount it

my $Partition = "/dev/$Drive" . "1";
my $Result = system ("mkfs -t ext2 $Partition");
if ($Result &gt; 0) {print "Error making partition, aborting.\n"; exit;}

   ### There should be better error checking here
system "umount /tmp/WIPE_IT";
system "rm -rf /tmp/WIPE_IT";
system "mkdir -p /tmp/WIPE_IT";
system "chmod 700 /tmp/WIPE_IT";

  ## See if we can mount the new partition.
my $Result = system ("mount $Partition /tmp/WIPE_IT");
if ($Result &gt; 0) {print "Error mounting drive, aborting.\n"; exit;}
system "chmod 700 /tmp/WIPE_IT";

#--------------------------------
### Now create the file and stop when we hit the size.

my $Count = 0;
my $Written_Size = 0;  

  ### Open up a new file.
open(FILE,"&gt;&gt;/tmp/WIPE_IT/Message.txt");
   ### If someone actually wants to screw around with your hard drive, 
   ### let us play with them and waste their time by adding a teaser. 
my $Ran = rand 259200000;   # between now and ten years ago (approx)
($Ran, $Junk) = split(/\./, $Ran, 2);
   ## New date minus random number of seconds
my $Date = `date --date '-$Ran seconds'`;

print FILE "DATE CREATED $Date\n";
my $Ran = rand 50;
($Ran, $Junk) = split(/\./, $Ran, 2);
$Ran = $Ran + 10;
print FILE "This document is extremely secure. It is a violation to let 
any unauthorized persons read it. Known password holders need to 
apply Method $Ran in order to decrypt binary data.\n"; 

  ### Create random number plus 25000
my $Ran = rand 25000;
($Ran, $Junk) = split(/\./, $Ran, 2);
$Ran = $Ran + 25000;

  ### Create an array of numbers which we will use most of the time.
my @Blank =  (1..$Ran);
  ### Take the array and make into a string.
my $Blank = "@Blank";
  ### Empty the array to free up memory.
@Blank = ();
my $B_Length = length $Blank;

  ### Let us get the amount of real space we have for the partition
my @Temp = `df`;
@Temp = grep($_ =~ /^$Partition/, @Temp);
my $Line = $Temp[0];
my ($Junk,$Blocks,@Junk) = split(/\s+/, $Line,4);
  ### We are assuming 1k blocks. 
my $Size = $Blocks*1000;

  ## While the file we have written is less than the size of the
  ## partition, print some more data. 
while ($Written_Size &lt; $Size)
  {
  $Count++;

        ### 9 out of ten times, we just want to print blank spaces to hurry
        ### up printing. One out of ten times, print garbage binary.
     my $Ran = rand (10);
     if ($Ran &gt; 1) 
       {
       print FILE $Blank; 
       $Written_Size = $Written_Size + $B_Length; 
       }  
     else 
       {
         ## This part makes a long string (upto 10000 bytes) of random data. 
       my $Garbage = "";
       my $Length = rand(10000);
       ($Length, $Junk) = split(/\./, $Length, 2);
       for (my $i = 0; $i &lt; $Length; $i++)
         {
         my $Ran = rand 256;
         ($Ran, $Junk) = split(/\./, $Ran, 2);
         $Garbage .= chr $Ran;
         }
         ## This parts encrypts the random data 8 bytes at a time. 
       my $Temp = $Garbage;
       my $Encrypted = "";
       while (length $Temp &gt; 0)  
         {
         while (length $Temp &lt; 8) {$Temp .= "\t";}
         my $Temp2 = $Blowfish_Cipher-&gt;encrypt(substr($Temp,0,8));
         $Encrypted .= $Temp2; 
         if (length $Temp &gt; 8) {$Temp = substr($Temp,8);} else {$Temp = "";}
         }

         ### Print the encrypted random data to file. 
       print FILE $Encrypted;
       $Length = length $Encrypted;

       $Written_Size = $Written_Size + $Length;
       my $Rest = $Size - $Written_Size;
       print "$Size - $Written_Size = $Rest to go\n";
       }

   ### At every 500 prints, start saving to a new file.  
  if ($Count =~ /500$/) 
    {
    close FILE;
    open(FILE,"&gt;&gt;/tmp/WIPE_IT/$Count");
    }
  }

close FILE;
#----------------------------------------------------

my $Result = system ("umount $Partition");
if ($Result &gt; 0) {print "Error unmounting partition $Partition, aborting.\n"; exit; }

  ### Let us reformat the partition. Doesn't delete data, just removes it
  ### from the directory. 
my $Result = system ("mkfs -t ext2 $Partition");
if ($Result &gt; 0) {print "Error making partition, aborting.\n"; exit;}


</pre>

<h3>
<a NAME="Conclusion"></a>Conclusion</h3>
Using Expect was not necessary (other programs could have solved
the simple problems I had). Using Blowfish was not necessary. As a matter
of fact, the whole darn script was way too long if you just wanted to
wipe a hard drive and fill it with blanks. However, I wanted to use
fdisk because I always want to use fdisk, Expect is such a powerful tool,
it is good to let people see how it works, and putting random garbage
 encrypted binary data in to confuse a hacker is just an extra touch. 
<p>
I don't understand the complete complexity of hard drives, so I am not
sure if there are residual data left on the hard drive.
For my purposes, and my level of security, it does exactly what
I need. As I develop MILAS more, I am sure there will be tighter checks
and enhancements to delete all data off of a hard drive.      
<p>
I tend to look forward in time trying to anticipate things which might be
needed in the future, which always causes a programmer to work more than is 
required for the project at hand. However, the mood struck me, and I like
the direction the script is going, and so, it doesn't bother me to write
up this article on an airplane flight. Making something cool doesn't
wear me out, unlike having to do work for someone else, which is real work.    


<h3>
<a NAME="REF"></a>References</h3>

<ol>
<li><a href="http://www.perl.com">Perl.com</a> website.
<li><a href="http://www.perl.com/CPAN-local/modules/by-category/21_File_Handle_Input_Output/Expect/Expect-1.10.readme">Expect Perl Module</a></li>
<li><a href="http://www.perl.com/CPAN-local/modules/by-category/14_Security_and_Encryption/Crypt/Crypt-Blowfish-2.06.readme">Blowfish Perl Module</a></li>
<li><a href="http://www.gnujobs.com/Articles/14/Wipe_It.html">Original site for this article. - http://www.gnujobs.com/Articles/14/Wipe_It.html</a> 
(any updates will be placed here)</li>
</ol>


<BLOCKQUOTE><EM>
	[You can also use /dev/random or /dev/urandom to overwrite
	a disk.  See<BR>
	<A HREF="../issue60/lg_answer60.html#tag/9">The Answer Gang: "Classified Disk - Low-level Format"</A>
	in issue 60.  But it doesn't do encryption.  -Mike.]
	</EM></BLOCKQUOTE>


<!-- *** BEGIN copyright *** -->
<P> <hr> <!-- P --> 
<H5 ALIGN=center>

Copyright &copy; 2001, Mark Nielsen.<BR>
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR> 
Published in Issue 63 of <i>Linux Gazette</i>, Mid-February (EXTRA) 2001</H5>
<!-- *** END copyright *** -->

<!--startcut ==========================================================-->
<HR><P>
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="nielsen.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="lg_toc63.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_frontpage.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue63/nielsen2.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom"  ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="nielsen3.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom"  ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->