Fri, 25 Jun 2010

Nuking a Rented Server


We recently upgraded one of the servers running our hosted filtering service. The old server was rented from our colocation provider; we own the new server.

The problem we faced was that after the move, we had to remove all data from the rented server remotely. We wanted to completely wipe the disks so no confidential information was left behind. And this had to be done without physical access to the machine.

Luckily, the filtering server was a Linux VServer on its own partition. So zeroing out the filtering server was easy; we just unmounted the partition and overwrote it with zeros. Clearing out the root partition was trickier; we had to nuke it while the system was running.

The solution was as follows:

Amazingly, nuke-block-device ran to completion. Naturally, the system hung up completely after it finished. While erasing the disks with nuke-block-device is not completely secure (you need something like Darik's Boot And Nuke for that), completely zeroing out all the disks makes it impossible for an attacker to recover the data without specialized equipment. And that was good enough for us!

The Code for nuke-block-device

Here's the source code for nuke-block-device. It's a quick hack, and is Linux-specific.

The following code is DESIGNED to destroy all data on a block device. DO NOT run it unless that is your intention!

#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <sys/mman.h>

#define MEGABYTE 1048576
#define SPIT_PERIOD 10

char buffer[MEGABYTE];

int
main(int argc, char **argv)
{
    unsigned long long size_in_bytes;
    unsigned long size_in_megabytes;
    unsigned long megabytes_done;
    int i;

    char *blockdev;
    int fd;

    if (argc != 2) {
	fprintf(stderr, "Usage: %s block_device\n", argv[0]);
	exit(1);
    }

    if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) {
	fprintf(stderr, "mlockall failed; continuing anyway: %s\n",
		strerror(errno));
    } else {
	fprintf(stderr, "mlockall succeeded.\n");
    }

    blockdev = argv[1];

    fd = open(blockdev, O_RDONLY);
    if (fd < 0) {
	fprintf(stderr, "Could not open %s: %s\n", blockdev, strerror(errno));
	exit(1);
    }
    if (ioctl(3, BLKGETSIZE64, &size_in_bytes) < 0) {
	fprintf(stderr, "ioctl failed: %s: Is %s a block device?\n",
		strerror(errno), blockdev);
	exit(1);
    }
    close(fd);

    printf("The capacity of %s is %llu bytes.\n", blockdev, size_in_bytes);
    size_in_megabytes = size_in_bytes / MEGABYTE;

    fd = open(blockdev, O_WRONLY);
    if (fd < 0) {
	fprintf(stderr, "Could not open %s for writing: %s\n", blockdev, strerror(errno));
	exit(1);
    }
    fprintf(stderr, "You have 10 seconds before all data on %s is IRRETRIEVABLY NUKED!\n", blockdev);
    for (i=10; i >0; i--) {
	fprintf(stderr, "... %d\n", i);
	sleep(1);
    }
    fprintf(stderr, "... 0!\n");
    fprintf(stderr, "Nuking %s!\n", blockdev);
    memset(buffer, 0, MEGABYTE);
    megabytes_done = 0;
    while(1) {
	ssize_t n = write(fd, buffer, MEGABYTE);
	if (n <= 0) break;
	megabytes_done++;
	if (!(megabytes_done % SPIT_PERIOD)) {
	    fprintf(stderr, "Done %lu megabytes of %lu.\n", megabytes_done, size_in_megabytes);
	}
    }
    close(fd);
    printf("%s is officially nuked.\n", blockdev);
    exit(0);
}

[permalink]


Blog    RSS    Home