5

I have a hard drive that went bad and before I send it for RMA I want to wipe as much as possible from it. I tried using windows utilities and also did dd of /dev/random. The problem is I can't wait for either of those solutions to finish as the reason for the RMA is that it writes at a max speed of 1 MB/Sec. It will take over 140 hours just to do a single pass of the 500GB hard drive.

I have been looking for a utility (or even a bash script on linux) that would pick sectors at random and write random data (or even zeros) to those sectors. I'm hoping that if I run this for 24 hours, that will wipe approximately 80 GB of data. Since it will be randomly chosen, all the bigger files will be impossible to recover and the smaller ones will either be wiped, will be missing chunks, or will possibly be recoverable. This is unfortunately the optimal solution for me at this point.

SOLUTION

Thanks to "evildead" I was able to get a lot of the data on the drive to be randomly filled with junk from /dev/urandom. The bash script, in case someone ever needs it, is below:

#!/bin/bash
while (true); do
    randnum=${RANDOM}${RANDOM}
    number=$((10#$randnum%976773168))
    echo -e $number >> progress.txt
    dd if=/dev/urandom of=/dev/sdx1 skip=$number count=1
done

You will need to replace 976773168 with the number of blocks on your drive. I originally tried $RANDOM in bash, but it is only a 16-bit int and therefore is only 32k. As I needed a number that is over 900 Million I combined two $RANDOM values, so for instance if my random numbers are 22,861 and 11,111 I get 2,286,111,111 then fitting it to my block size I get a pretty random value in my range. It doesn't have perfect entropy but then again, what is really random on a computer? ;) The 10# is there in case the first random number is a 0, it forces bash to use base 10, not base 8, which is what it uses if it thinks the number is an octal (leading zero). I also write the random numbers to a file for analysis later to see what the spread was. If you don't need this you can just take out

echo -e $number >> progress.txt

and it will run fine. Also dont forget to replace sdx1 with the actual drive or partition you want to work on. I hope this is helpful for someone, I know it was really helpful for me.

Marcin
  • 245
  • 1
  • 3
  • 9

7 Answers7

7

you can use a shellscript in combination with dd.

e.g.

 while (true); do
   number=$((($RANDOM * 32768 + $RANDOM)))
   dd if=/dev/urandom of=/dev/sdx1 seek=$number count=1
 done

You only have to modify the number which is generatet from $RANDOM to fit to your Blocks.

EDIT 2016: Please note, the old solution was incorrect. Because we want to overwrite a byte at a random position in the output stream, we have to use seek instead of skip, as mentioned in the comments.

evildead
  • 892
  • 5
  • 11
  • 1
    Did you ever hear of software that does this? Cause I haven't and it seems like at least some people would find it useful. – Marcin Nov 21 '09 at 20:44
  • Worked great, I made some changes to the script for my situation, I added them to my question in case someone else had to use it in the future. Thanks for your help. – Marcin Nov 22 '09 at 10:58
  • Hi, I never had such a problem and so I never heard about any software to solves such a problen. I knew dd can skip blocks and supports limit wirtes with count. So the only problem was to get a random number and putting everything together. :) – evildead Nov 23 '09 at 00:13
  • 1
    The accepted solution is plain wrong. You have to use "dd seek" instead of "dd skip", otherwise it make no sense: you will be writing to the same block while you need to write to random block. Here's an excerpt from documentation: > seek=n Seek n blocks from the beginning of the output before copying. On non-tape devices, an lseek(2) operation is used. Otherwise, existing blocks are read and the data discarded. If the user does not have read permission for the tape, it is positioned using the tape ioctl(2) function calls. If the seek operation is past the end of file, space from the current en – Sergey Kovalev Aug 11 '16 at 21:31
  • wow, it seems you are absolutely right. I will change that. Thank you. – evildead Aug 13 '16 at 09:54
2

My system isn't broken and writing from /dev/random is about 650Kb/s. Writing from /dev/urandom is 7Kb/s.

I've worked this issue for myself and for a purely bash solution you have to be realistic about what your goal is because unless your goal is to learn how to do it in bash because the point is doing it ALL in bash, the objective of wiping a disk securely is better accomplished in other ways though bash is useful in the solution.

evildead's bash algorythm to randomly select where dd will write to the drive works however, /dev/urandom is significantly slower than /dev/random and I think it is less secure to pepper the drive with chunks of random data and I think it will be harder to retrieve data from a wiped drive if you quickly do two passes writing one's then zeros to it.

For myself I wrote ones to the drive with:

tr '\0' '\377' < /dev/zero | pv > /dev/sdz

then I wrote zeros to the drive with:

pv < /dev/zero > /dev/sdz

Note the use of pv. It's a great program though you have to install it on most systems. Easy to find, doesn't seem to come with a man page but there is one on-line. It shows the progress of data passing through a pipe and with some programs you can even set it to stop after a certain amount of data is passed.

THEN purely because I was irritated that no bash solution would write random numbers as fast as either of those writes above would do, I wrote a small C program called svrandom to generate random numbers QUICKLY which I called from bash as follows:

while :; do ./svrandom; done  | pv > /dev/sdz

On my system that fills drive /dev/sdz with random numbers as fast as writing /dev/zero does. Goal of wiping drive with random numbers achieved, and bash was used in the solution.

/* svrandom
a small program from shadowvision.com September 2015 to generate strings of random numbers.
the default setting of 10000000 gives about 453 megs, adjust as 
needed */ 

#include <stdio.h>
#include <stdlib.h>
int main()
{
int r,a,b;
 /* adjust following number as needed to suit your string length */
 for(a=0;a<10000000;a++)
 {
 for(b=0;b<5;b++)
 {
 r=rand();
 printf("%d",r);
 }

 }
 return(0);
}

In the source I mention that you can control the length of the random number string by adjusting a number. If you call it from a while loop you wont have to although there may be a carriage return at the end of each loop, but if you want one continuous string from just the program you will have to change the number.

snip! looking around I found this solution on https://superuser.com/questions/19326/how-to-wipe-free-disk-space-in-linux

openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt < /dev/zero |pv > /dev/sd{x}

and like the guy there said, I can't believe how fast this is. It's writing to the disk faster than I thought the disks maximum write speed was.

It looks to me that this command is using openssl to encrypt a string of zeros from /dev/zero using /dev/urandom as the seed but im not 100% sure. my solution with the C program to write random numbers writes to my system at 82mbps, this openssl solution is writing at 100mbps. wow!

unifex
  • 21
  • 2
  • I think your system is a bit broken if `/dev/urandom` can only supply data at 7kB/s. On my system it gives a nice, steady 4.8MB/s, according to `pv`. But +1 from me for a nice first answer - welcome to Server Fault! (And I hope you'll forgive me for marking it up a bit.) – MadHatter Sep 24 '15 at 14:19
1

A Python 3 script, with:

  • awareness of block device size
  • verification of block device size, by writing bytes at the boundaries
  • guarantee of first and last byte destroy
  • random data overwrites
  • random offset
  • random batch sizes

If you need Python 2 then it should be easy to covert by using "".format() instead of f"" strings.

import subprocess
import random


REPS = 100
CRASH_ON_FIRST_FAILURE = True  # change to False if the device is not reliable

def run(*cmd, assert_returncode=None, print_stderr=False):
    completed = subprocess.run(cmd, capture_output=True)
    if assert_returncode:
        assert completed.returncode == assert_returncode, f"Unexpected return code (got={assert_returncode}, expected={assert_returncode})"
    if print_stderr:
        print(str(completed.stderr))
    return completed.stdout


def part_size(part):
    """
    Partition size in bytes
    """
    return int(run("blockdev", "--getsize64", part))


def destroy_block(part, bs, seek, assert_returncode=None, print_result=False):
    run(
        "dd", f"bs={bs}", "if=/dev/urandom", f"of={part}", f"seek={seek}", "count=1",
        assert_returncode=assert_returncode
    )
    if print_result:
        print(f"Destroyed bs={bs} of={part} seek={seek}")


def destory_random_block(part, part_size, bs):
    """
    bs=1 destroys bytes sized block
    bs=1024 destroys KB sized block
    etc.
    """
    seek_max = int(part_size / bs)
    seek = random.randint(0, seek_max)
    if CRASH_ON_FIRST_FAILURE:
        assert_returncode = 0
    else:
        assert_returncode = None
    destroy_block(part, bs=bs, seek=seek, assert_returncode=assert_returncode)


def destroy(part):
    """
    part - partition to be destroyed
    """
    s = part_size(part)
    destroy_block(part, bs=1, seek=s, assert_returncode=1)  # "test" destroying 1 byte at size boundary, should fail
    destroy_block(part, bs=1, seek=(s - 1), assert_returncode=0, print_result=True)  # "test" destroying 1 bytes before boundary, should pass
    destroy_block(part, bs=1, seek=0, assert_returncode=0, print_result=True)  # "test" destroying first 1 byte
    while True:
        print(f"Destroying {REPS} byte-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=1)
        print(f"Destroying {REPS} KB-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=1024)
        print(f"Destroying {REPS} MB-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=(1024 * 1024))
        rand_size = random.randint(1, 1024 * 1024)
        print(f"Destroying {REPS} {rand_size}-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=rand_size)
        print("\nRise and repeat\n\n")


destroy("/dev/sdb1")



Example output:

# "test" destroying 1 byte at size boundary, should fail
# "test" destroying 1 bytes before boundary, should pass
Destroyed bs=1 of=/dev/sdb1 seek=10736369663
# "test" destroying first 1 byte
Destroyed bs=1 of=/dev/sdb1 seek=0

Destroying 100 byte-sized blocks
Destroying 100 KB-sized blocks
Destroying 100 MB-sized blocks
Destroying 100 875091-sized blocks

Rise and repeat


Destroying 100 byte-sized blocks
Destroying 100 KB-sized blocks
Destroying 100 MB-sized blocks
Destroying 100 1028370-sized blocks

Rise and repeat

To run:

  1. Copy the source code all but the last line
  2. On the victim host log-in as root
  3. On the victim host run: python3
  4. Paste the code from step 1
  5. Type destroy("/dev/XYZ") and return key twice
  6. After a few hours, hit Ctrl-c

NOTE: "/dev/XYZ" is the partition name that will lose data.

WARNING: Watch out for Fat-finger errors. The data will be gone forever so double-check what partition you are typing in.

WARNING: Running this script for days in cloud services may cost if you are charged for disk write IOPs.

Aleksandr Levchuk
  • 2,415
  • 3
  • 21
  • 41
1

If you have a powerful magnet, you can physically wipe it.

I take apart old, dead hard drives and get the voice coil magnets from the head positioning assembly. These are rare earth magnets, and from a typical 3.5" drive they're powerful enough to erase enough of the servo tracks on a hard drive so it'll be completely unusable.

One way or another, get the magnet, wipe it back and forth over the top cover of the drive and in less than a minute you'll have a dead drive. Since it's being RMA'd anyway, they shouldn't care.

Ward - Reinstate Monica
  • 12,788
  • 28
  • 44
  • 59
1

The best software that will automate this process is Darik's Boot and Nuke (aka DBAN)

It's a boot CD with a comprehensive range of drive-wiping mechanisms, ranging in aggresiveness (And time taken to wipe the drive)

It is available from http://www.dban.org/

justinsteven
  • 506
  • 2
  • 6
0

Thanks for the solution on top!
Since I am not allowed to comment the answer with the script I have to add my tiny enhancement myself.
I just tuned it a little for more convenience so that one only has to define the device. fdisk will deliver the number of sectors:

#!/bin/bash
# add device to mangle
# example: 
# disk=/dev/sde
disk=
# get number of sectors
sectors=$(fdisk $disk -l| head -1| awk '{print $7}')
# run
while (true); do
    randnum=${RANDOM}${RANDOM}${RANDOM}
    number=$((10#$randnum%$sectors))
    echo -e $number >> progress.txt
    dd if=/dev/urandom of=$disk seek=$number count=1
done
-1

The dban option is the correct answer to this problem.

Writing "random" data from /dev/random will run into problems on most systems because you'll exhaust the entropy on the system and wind up writing the data very slowly.

Almost as "random" as from /dev/random is to encrypt a string of zeros with a random passphrase. You can use dd and openssl to do this, and it allows you to nuke the disks as fast as the system is able to write to disk (instead of waiting on /dev/random). You'll be able to run this 3-5 times in the same time you'd run something that's just dding from /dev/random.

dd if=/dev/zero | openssl des > /dev/hda13
chris
  • 11,784
  • 6
  • 41
  • 51
  • I don't understand how people constantly ignore part of the question on here. I am writing at 1 MB/Sec because the drive is broken. /dev/urandom provides data at a higher rate than that. dban is not the correct answer because it doesn't write to random sectors, it writes linearly sector by sector. It might write random DATA but it doesn't write it in a random ORDER. – Marcin Nov 22 '09 at 20:55
  • you can use /dev/urandom or /dev/zero, doesn´t really matter. Only thing not to use is definatly /dev/random, cause it blocks if entropy is exhausted. – evildead Nov 23 '09 at 00:20