My Awesome Secure and Portable System (2009)
Many people have asked about how my incredibly complex, but awesome personal operating system works. It's so complicated that I can usually only explain it in little bits, and I always forget to mention one of the many things that make it awesome. Instead of coming up with everything on the fly, I'm writing this article to explain, in depth, how my system works, what makes it awesome, and provide the scripts and configurations I've written to make this system work.
For those who aren't as technically inclined, I'll start with a general overview and a neat-o feature list. This isn't something your grandmother will be able to read, it still requires some knowledge of the inner workings of computers. As for the one person who might be able to understand how the technical details work and want to attempt to replicate my system, everything will be laid out in detail after that.
I designed this system with both security and portability in mind. My system uses a
Linux kernel and the entire thing, applications, personal data, etc, takes up 1GB of space. It is split up into two parts, the operating system, and my personal data. The operating system is a 700MB live-CD,
GRML, that generates a completely fresh install every single time I boot up the computer. Doing this means that if my system is ever hacked into, a simple restart of my computer fixes the problem. This also means that any configuration changes made or private information stored by any application, restarting reverts everything to a clean slate.
This leaves 300MB for personal data, which might not sound like much, but when you cut out all multimedia files and store them elsewhere, this is quite a lot. At the time of writing, I currently use 96MB of this, most of which is addon packages to improve functionality of the operating system.
The personal data is encrypted using an AES-256 algorithm. The password I type in actually unlocks a special encrypted file which unlocks the real encryption information, meaning that my actual password is never stored in RAM (more specifically, DRAM). To prevent highly sensitive information from being discovered by remote hackers, which this layer of encryption would not protect against, an extra layer of encryption using either GPG or AES-256 provides two layers of encryption for highly sensitive data.
Because the system is so small, I have a backup script that generates compressed, encrypted backups that can be uploaded and stored anywhere. This only backs up the personal data portion, which contains all of my system configuration and personal data. The operating system can just be redownloaded, so it is unnecessary to backup. This means that my backup files are approximately 30-50MB in size, and are extremely portable.
Also along the lines of portability, since the entire operating system and data is 1GB total, I have a small USB drive that I carry around with me that contains a complete copy of my entire system. By plugging it into any computer which supports USB booting (most computers do), I can use my system anywhere. I wrote a synchronization script to keep the USB drive up to date, so at all times it has all of my most recent data. If I make any changes to it, I can synchronize it back to my main system, so it is fully editable when I'm not on my main system.
Be warned, do NOT try to build this system unless you are prepared to work on it for days. This system is the result of an ongoing two years work, so don't get mad or frustrated if you can't get it to work. Extensive Linux and shell scripting experience is required for getting this working, since this is not a step-by-step tutorial but a detailed system outline and my system is so tightly intertwined. Chances are, even some kernel hackers might have problems getting this working properly, though most should be able to figure it out. This shouldn't be too difficult to follow if you are just reading, though. This is more for my personal reference and curious minds.
I will be describing how my USB drive is set up for most of this technical outline. My main system has so many weird partitions that explaining that would provide tons of unnecessary information. These scripts have been tested with, and assume usage of GRML version 1.1.
DISCLAIMER: I am not responsible if you destroy your computer trying to recreate this system.
In the overview, I said the system is divided into two parts: the operating system, and personal data. This is not entirely true. There are actually three partitions associated with this. The remaining space on my USB drive is allocated for standard USB space for transferring data and other general data storage purposes.
Partition Table:
primary partition 1 - FAT32 - ~7GB
primary partition 2 - FAT32 - ~750MB - boot flag
logical partition 5 - FAT32 - ~3MB
logical partition 6 - AES-256 ENCRYPTED ext2 - ~300MB
Primary partition 1 is the extra partition used for standard USB storage.
This partition is simply a direct copy of the contents of the GRML live-CD, and has the boot flag set so that it is the partition booted.
The Syslinux configuration was modified slightly to take advantage of some boot-options GRML provides. For the startup scripts to work correctly, the partition the scripts are located on needs to be specified with the "myconfig" boot option to GRML. Because of this, there are three different boot options that I have available. The first is for my main system, the second is for booting from USB on a computer that has a SCSI drive, and the third is for booting from USB on a computer that has an ATA/IDE drive or no drive. The reason the difference exists for the second and third options is that the USB device will be detected after any SCSI devices, and will get a different name depending on the system. The second option uses "myconfig=/dev/sdb5", and the third option uses "myconfig=/dev/sda5", both referencing
Logical Partition 5 on the USB device.
This partition is the one unmentioned in the overview. This partition contains startup scripts to initialize the encryption, and stores the encrypted file containing the real password information.
Directory Listing:
-rwxr-xr-x 1 root root 798 2007-09-21 00:17 grml.sh
-rwxr-xr-x 1 root root 1378 2007-09-21 00:17 smount
-rwxr-xr-x 1 root root 1048576 2008-03-10 20:22 .ss
The "myconfig" boot-option is provided by
Primary Partition 2, and GRML executes "grml.sh" in the partition specified (this one).
This file mounts the
Secure Home directory from
.ss using
smount, removes the GRML device from the fstab, executes
system-work, then disables the grml-quickconfig script which comes up on startup for a normal GRML boot.
system-work is not directly executed. "grml.sh" is called in the middle of the standard GRML startup, so some of the other GRML startup commands are executed after "grml.sh".
system-work must be executed after all of these startup commands, so the only way around all of this is to overwrite root's ".zshrc" with a call to
system-work. By doing this, GRML will execute all startup commands, start up zsh like normal, then execute
system-work at the proper time.
Contents: grml.sh
#!/bin/bash
# get running grml partition
grml_part="`mount | grep " on /mnt/grml " | cut -d ' ' -f1`"
grml_partnum="`echo $grml_part | sed -r "s/.*([0-9]+)/\1/g"`"
grml_dev="`echo $grml_part | sed -r "s/(.*)[0-9]+/\1/g"`"
grml_part="$grml_dev$grml_partnum"
# get the device partition plus X
function grml_devplus(){
new="$grml_partnum"
let new+=$1
echo $grml_dev$new
}
# mount secure home
clear
bash /mnt/grml/smount /mnt/grml/.ss "`grml_devplus 1`" /home/sechome 0
# /etc/fstab fixer
mv /etc/fstab /etc/fstab.old
cat /etc/fstab.old | grep -v "`grml_devplus 0`" > /etc/fstab
rm /etc/fstab.old
# system-work
echo "bash /home/sechome/grml/system-work "`grml_devplus 0` > /root/.zshrc
# disable grml-quickconfig
echo > /usr/sbin/grml-quickconfig
The "smount" file is used to mount a helper file/partition, then use the files within to mount a secure partition. This, as described earlier, ensures that the real password is not stored in RAM or DRAM, and makes a harder to crack main partition (in theory, anyway).
"smount" takes three or four arguments. The first is the helper file, the second is the data partition, and the third is the destination mount point. An optional fourth argument can be specified which tells the script how many times the use has to guess the correct password before failing. The default is 4, and 0 means try forever (0 is passed in from
grml.sh).
Contents: smount
#!/bin/bash
# these aren't the values I use
LO_ICK_UNLOCK=1234
LO_ICK_REAL=5678
unlock_source="$1"
data_source="$2"
destination="$3"
# total tries
if [ -z "$4" ]; then tottries="4"; else tottries="$4"; fi
if [ "$4" = "0" ]; then tottries=""; fi
# get new loopback device
function get_loopdev(){
loop_devs=`ls -d /dev/loop*`
for loop_dev in $loop_devs; do
[ ! -b "$loop_dev" ] && continue
ret="`losetup $loop_dev 2> /dev/null`"
[ -z "$ret" ] && echo $loop_dev && break
done
}
# quit cleanly
function quit_clean(){
umount /tmp/usbtemp &> /dev/null
losetup -d $unlock_loop &> /dev/null
rmdir /tmp/usbtemp
exit
}
# secure home
if [ -e "$unlock_source" ] && [ -e "$data_source" ]; then
# modules
modprobe cryptoloop
modprobe aes_i586
# home-setup
unlock_loop="`get_loopdev`"
mkdir /tmp/usbtemp
tries=0
while
[ ! -e "/tmp/usbtemp/pwfile" ] &&
([ -z "$tottries" ] || [ "$tottries" -gt "$tries" ])
do
losetup -d $unlock_loop &> /dev/null
losetup -e aes-256 -C $LO_ICK_UNLOCK $unlock_loop $unlock_source
mount $unlock_loop /tmp/usbtemp &> /dev/null
let tries+=1
done
if [ ! -e "/tmp/usbtemp/pwfile" ]; then quit_clean; fi
home_loop="`get_loopdev`"
[ ! -d "$destination" ] && mkdir "$destination"
cat /tmp/usbtemp/pwfile | \
losetup -e aes-256 -C $LO_ICK_REAL -p 0 -S "`cat /tmp/usbtemp/seedfile`" \
$home_loop $data_source
mount $home_loop "$destination"
chown root.root "$destination"
chmod 755 "$destination"
quit_clean
fi
The ".ss" file is the encrypted helper file.
grml.sh calls
smount with this file as a parameter, using it to mount the actual partition. ".ss" is read using it as an encrypted loopback file (Linux cryptoloop module), then has it's own encrypted FAT32 filesystem within it. This can be seen by examining
grml.sh and
smount in detail.
Directory Listing:
-rwxr-xr-x 1 root root 73 2006-03-18 16:32 pwfile
-rwxr-xr-x 1 root root 73 2006-03-18 16:34 seedfile
"pwfile" is a file containing the password string for the real encrypted partition, and "seedfile" is a file containing the seed string for the real encrypted partition. These are used by
smount.
Contents: pwfile and seedfile
What, do you think I'm stupid? I'm not giving you this!
These files are intentionally complex to improve the encryption. Because these files are so complex, I developed a system for regenerating them if I ever need to. For more information about my password-file generation method, see
A.1: Password-File Generation.
This partition is mounted through
smount, and is an encrypted ext2 filesystem which contains all of the important stuff. The contents of this partition are described in detail later in
Secure Home.
The secure home directory (/home/sechome/) is where everything important is stored. When
Backups are made, this directory is tarred up and encrypted.
Directory Listing of /home/sechome/:
drwxr-xr-x 2 root root 1024 2008-03-09 13:34 addons/
drwx------ 5 grml grml 2048 2008-02-04 16:52 docs/
drwxr-xr-x 3 root root 1024 2008-03-09 13:56 grml/
drwxr-xr-t 17 grml grml 1024 2008-01-06 08:39 proj/
drwxr-xr-t 4 grml grml 2048 2007-10-25 11:12 scripts/
drwx------ 6 root root 1024 2006-08-06 08:53 .staticfs/
drwx-----T 19 root root 1024 2008-03-10 20:13 .statichome/
drwx-----T 6 root root 1024 2008-03-09 14:24 .staticroot/
drwxr-xr-x 23 grml grml 3072 2008-02-13 18:27 www/
This is not a complete directory listing of this directory. I took some things out that are completely irrelevant, and left some other irrelevant things in for examples of how this could be used.
For instance, "docs" is just a directory to store documents. "proj" is a directory to store GIT repositories of my projects. "scripts" is a ton of scripts that are useful, but I've never taken the time to make full projects out of them. "www" is the document root for apache2, with some symbolic links to other locations such as Surrogafier in "proj". "proj" and "scripts" have the sticky-bit set so that GIT or even I don't create files that are root owned on accident.
Please note, this is NOT the user's home directory. This is a backend directory that stores everything. The user's home directory is dynamically generated, and more information about this as well as the directories ".staticfs", ".statichome", and ".staticroot" can be found later in
Virtual Directories.
Used by
system-work, this directory contains a cramfs loopback file that contains installed addon Debian packages. This cramfs filesystem is appended to the aufs root filesystem.
The "grml" directory stores scripts that help set up and maintain the system.
Directory Listing of /home/sechome/grml/:
drwx------ 2 root root 16384 1969-12-31 18:00 booter/
-rwx------ 1 root root 167 2008-03-15 12:04 local-startup-after
-rwx------ 1 root root 197 2008-03-15 12:06 local-startup-before
-rwxr-xr-x 1 root root 33478 2008-03-09 14:39 my-grml-x
-rwx------ 1 root root 1227 2008-03-15 14:08 static-copy
-rwx------ 1 root root 2384 2008-03-14 15:32 sync-os
-rwx------ 1 root root 850 2008-03-15 12:06 system-work
-rwx------ 1 root root 282 2008-03-14 15:31 virtfs-init
"booter" is a directory that is bind mounted by
system-work to
Logical Partition 5. This directory is there for the
Backups system to be able to backup all data associated with the system.
"local-startup-after" and "local-startup-before" are files containing other startup commands that only apply to me, so they aren't given in this document. "local-startup-before" is called at the start of
system-work, and "local-startup-after" is called at the end.
my-grml-x is described in depth under
Miscellaneous Security.
static-copy is described in depth under
Virtual Directories.
sync-os is described in depth under
Synchronization.
This file is called by
grml.sh, and initializes the userland part of the system.
This file calls a local startup file, then mounts /dev/sda1 on /vault/. This directory will always contain the main partition of the local drive, or if the drive is ATA/IDE based and I'm booting from my USB drive, primary partition 1 of my USB drive. This is usually the place multimedia and other documents would be stored on the computer I'm working on.
From here, extra Debian addon packages are appended to the aufs root filesystem from
/home/sechome/addons/.
virtfs-init is called, then the "booter" directory is mounted for the
Backups system. Then some work is done for
my-grml-x and more local startup commands are run.
This file ends by killing zsh. The reason for this is that
grml.sh initializes this file by calling bash from ".zshrc". After this file is done,
virtfs-init will have replaced root's ".zshrc" with the one in ".staticroot", as described in
Virtual Directories. Therefore, zsh needs to be restarted so the right configuration file will be used. After this step, the user has control of the system after logging in due to the
Console Security.
my-grml-x can be called, or whatever the user wants to do.
Contents: /home/sechome/grml/system-work
#!/bin/bash
# local-startup-before
bash /home/sechome/grml/local-startup-before
# /vault
mount /dev/sda1 /mnt/sda1
[ ! -z "`ls /mnt/sda1`" ] && mkdir /vault && mount --bind /mnt/sda1 /vault
# setup addons cramfs, then append to aufs
if [ -e "/home/sechome/addons/addons.cramfs" ]; then
mkdir /live/addons
cp /home/sechome/addons/addons.cramfs /live/addons.cramfs
mount -o loop -t cramfs /live/addons.cramfs /live/addons
mount -o remount,append:/live/addons=ro /
fi
# initialize virtual filesystem stuff
bash /home/sechome/grml/virtfs-init
# mounts the 'boot' partition to an easily accessed and backed up directory
bootdev="$1"
bootname="`echo "$bootdev" | cut -d '/' -f3`"
mount $bootdev /mnt/$bootname
mount --bind /mnt/$bootname /home/sechome/grml/booter
# my-grml-x
ln -s /home/sechome/grml/my-grml-x /usr/bin/my-grml-x
# local-startup-after
bash /home/sechome/grml/local-startup-after
# teh edn
(sleep 0.5; killall -9 zsh) &
disown
This file creates the process described in
Virtual Directories. There is an optional argument, "nofs", which will prevent the script from utilizing ".staticfs". This option is used by
sync-os.
Contents: /home/sechome/grml/virtfs-init
#!/bin/bash
# home-work
rm -rf /home/grml
cp -r /home/sechome/.statichome /home/grml
chown -R grml.grml /home/grml
# root-work
rm -rf /root
cp -r /home/sechome/.staticroot /root
chown -R root.root /root
# fs-work
if [ "$1" != "nofs" ]; then
cp -r /home/sechome/.staticfs/* /
fi
Any application can store logs, private information, and other random status files in a user's home directory. These files are unnecessary for the most part, and can increase wear on a device such as a USB drive, especially if all of the information is to be encrypted before being stored. To prevent unnecessary wear, and to reduce logging of personal data, I leave the user's home directory as a part of the ramdisk generated by the operating system. The directories ".statichome" and ".staticroot" are copied over to the ramdisk by
virtfs-init, then any changes that are made by any application are removed when the system is shut down. The same thing is done for the root filesystem ("/") with the directory ".staticfs".
Examples of what could be in a static home directory are basically anything that would be in a user's home directory, such as various configuration directories and files. The extra directories such as "docs" for storing documents and such as described in
Secure Home can be symbolically linked to in ".statichome". That way documents can be organized into logical categories and not be required to be saved like configuration files.
Because some configuration changes might need to be stored permanently, there needs to be a system to store configuration files in the static directories. This functionality is provided by the "save-fs", "save-home", and "save-root" commands.
Since the separation between dynamic and static files exists anyway, another set of commands is provided to revert the files in the dynamic directory back to the static versions. These commands are "revert-fs", "revert-home", and "revert-root".
These commands can only be run as root, and are stored as aliases in root's ".zshrc". These aliases are aliases for different argument calls to the script
static-copy.
Alias Definitions:
alias revert-fs="/home/sechome/grml/static-copy revert /home/sechome/.staticfs /"
alias revert-home="/home/sechome/grml/static-copy revert /home/sechome/.statichome /home/grml"
alias revert-root="/home/sechome/grml/static-copy revert /home/sechome/.staticroot /root"
alias save-fs="/home/sechome/grml/static-copy save /home/sechome/.staticfs /"
alias save-home="/home/sechome/grml/static-copy save /home/sechome/.statichome /home/grml"
alias save-root="/home/sechome/grml/static-copy save /home/sechome/.staticroot /root"
The user would type out one of these aliases, and follow it with a file that they wish to save or revert.
This file saves and reverts files to and from the static directories. This command requires 4 arguments.
The first argument specifies what action is to be taken, "save" or "revert".
The second argument specifies the static directory associated with the action.
The third argument specifies the dynamic directory associated with the action.
The fourth argument specifies the filename of the file to be copied in either direction. In the alias definitions, these are left off and the user specifies which file is to be stored.
NOTE: Be extremely careful with this command, and in fact, I recommend never calling this command directly. Use the aliases provided above, unless you really know what you are doing. The reason for this is that "rm -rf" is called within the file, and if you type in something that I didn't think of preventing, you could destroy your computer. I've attempted to prevent obvious problems such as "/" and "/*", but you could still do damage if you type in the wrong thing.
Contents: /home/sechome/grml/static-copy
#!/bin/bash
command="$1"
staticdir="$2"
dynamicdir="$3"
filename="$4"
if [ -z "$filename" ]; then
echo Error: No file specified.
exit
fi
if [ -z "$staticdir" ]; then
echo Error: No static directory specified.
exit
fi
if [ -z "$dynamicdir" ]; then
echo Error: No dynamic directory specified.
exit
fi
if [ "${filename:0:1}" = "*" ]; then
echo "Error: That could be dangerous... catastrophe averted."
exit
fi
if [ "$command" = "revert" ]; then
origindir="$staticdir"
destdir="$dynamicdir"
prompt="Really revert file '$filename' to static directory version? "
waitmsg="Reverting file to static directory version... "
elif [ "$command" = "save" ]; then
origindir="$dynamicdir"
destdir="$staticdir"
prompt="Really save current file '$filename' to static directory? "
waitmsg="Saving file to static directory... "
else
echo Error: Unknown command.
exit
fi
[ ! -e "$origindir/$filename" ] && \
echo "No such file or directory '$filename' in '$origindir'" && exit
echo -n "$prompt"
choice=`bash -c "read -n 1 choice; echo \\$choice"`
echo
if [ "$choice" = "y" ]; then
echo -n "$waitmsg"
rm -rf "$destdir/$filename"
cp -ar "$origindir/$filename" "$destdir/$filename"
echo Done
else
echo Quitting
fi
The system is set up so that everything is contained within
/home/sechome/. The only thing that isn't in this directory is the boot partition, which is why
system-work bind mounts this partition to /home/sechome/grml/booter/.
Since everything is contained like this, a simple compressed tar archive can be created, piped through aes-pipe, and stored as a file. Decryption, too, is as simple as piping the contents of a file through aes-pipe, then back through the tar command. Because this is such a simple operation, these commands, "encbkup" and "decbkup", can be expressed as simple functions in ".zshrc".
"encbkup" takes no arguments, and "decbkup" takes one argument, the file to be decrypted and uncompressed. This spits out the contents of the backup into the current directory.
encbkup and decbkup:
# these aren't the values I use
BKUP_ICK=1234
BKUP_SEED=5678
function encbkup(){
(tar cj /home/sechome | \
aespipe -e aes256 -C $BKUP_ICK -S $BKUP_SEED -T) \
> "bkup`date +%Y%m%d`";
}
function decbkup(){
(aespipe -d -e aes256 -C $BKUP_ICK -S $BKUP_SEED < "$1") | \
tar xj;
}
Synchronization is performed by specifying a direction and device to synchronize the current running instance of the system with. Currently, synchronization is a one way action, so if different changes were made on two different systems, any synchronization actions performed would clear any changes on one of the two systems depending on what is specified.
I have not had any desire to change this since it is much easier and much clearer to know what device is at what state if only one can be edited at a time. Because this is a single user system, this shouldn't be an issue unless the USB device is lost after making changes to something.
This file is used to perform the actual task of synchronization. This file is called manually by the user, and takes two arguments.
The first argument is the direction the synchronization is to be performed, "to" or "from".
The second argument is the secondary device that is not associated with the currently running system.
For example, running "sync-os to <USB_DEVICE_FILE>" when booted into a hard drive install would copy the hard drive data over to the USB device.
This script unmounts and remounts the booter partition, and synchronizes that separately since the secondary device will not have that device mounted correctly, and I don't trust rsync to traverse that correctly anyway. After synchronizing using rsync, everything is put back into its original place. Sychronizing "from" a device also performs one more step, reinitialization of the
Virtual Directories with the exception of the root filesystem directory ".staticfs". This is done by calling
virtfs-init with the "nofs" option. I've tried letting it reinitialize the virtual root filesystem directory, but it breaks things and causes crashes, so it's not very safe.
Contents: /home/sechome/grml/sync-os
#!/bin/bash
if [ "$1" != "to" ] && [ "$1" != "from" ]; then
echo "First argument must be 'to' or 'from'."
exit
fi
if [ -z "$2" ]; then
echo "Second argument must point to GRML partition."
exit
fi
action="$1"
n_booter_dev="$2"
SYNC="rsync -arvuz --delete-before"
SYNC_MSDOS="rsync -rvuz --delete-before"
device="`echo $n_booter_dev | sed -r "s/(.*)[0-9]+/\1/g"`"
partnum="`echo $n_booter_dev | sed -r "s/.*([0-9]+)/\1/g"`"
function devplus(){
new="$partnum"
let new+=$1
echo $device$new
}
function chr(){ echo "print chr($1)" | python; }
function gen_randnum(){ let "rand=$RANDOM%($2-$1+1)+$1"; echo $rand; }
function gen_randstr(){
cnt="$1"
newstr=""
i=0; while let i+=1 && [ "$i" -le "$cnt" ]; do
rand="`gen_randnum 0 61`"
let rand+=48
[ "$rand" -ge "58" ] && let rand+=7 && [ "$rand" -ge "91" ] && let rand+=6
newstr="$newstr`chr $rand`"
done
echo $newstr
}
if
[ ! -b "$n_booter_dev" ] ||
[ ! -b "`devplus 1`" ]
then
echo "Partition requirements not met."
exit
fi
randstr="`gen_randstr 5`"
TMP="/tmp/$randstr"
# quit cleanly
function quit_clean(){
if [ ! -z "$1" ]; then echo "Sync-ing booter partition..."; fi
umount $TMP-n_booter &> /dev/null
rmdir $TMP-n_booter &> /dev/null
if [ ! -z "$1" ]; then echo "Sync-ing encrypted partition..."; fi
umount $TMP-sync-to &> /dev/null
rmdir $TMP-sync-to
devplus1="`devplus 1`"
lodev="`losetup -a | grep $devplus1 | cut -d ':' -f1`"
if [ -b "$lodev" ]; then losetup -d $lodev; fi
sync
exit
}
# get booter mount
booter_mount="`mount | grep booter | cut -d ' ' -f1`"
# prepare/mount booter partition
mkdir $TMP-n_booter
chmod 700 $TMP-n_booter
mount $n_booter_dev $TMP-n_booter
# prepare/mount encrypted partition
mkdir $TMP-sync-to
chmod 700 $TMP-sync-to
bash /home/sechome/grml/booter/smount /home/sechome/grml/booter/.ss `devplus 1` $TMP-sync-to 3
# test mount
if [ -z "`mount | grep $TMP-sync-to`" ]; then
echo "Mount failed."
quit_clean
fi
# umount booter partition in sechome
umount /home/sechome/grml/booter
# sync partitions
if [ "$action" = "from" ]; then
# sync 'from'
$SYNC_MSDOS $TMP-n_booter/ $booter_mount
$SYNC $TMP-sync-to/ /home/sechome
bash /home/sechome/grml/virtfs-init nofs
else
# sync 'to'
$SYNC_MSDOS $booter_mount/ $TMP-n_booter
$SYNC /home/sechome/ $TMP-sync-to
fi
# remount booter partition
mount --bind $booter_mount /home/sechome/grml/booter
quit_clean 1
This section describes security functions in the system which are not a direct part of setting up the system itself, but are still important security measures within the system.
Because GRML is a live-CD, sudo works to gain root access to anything. On top of which, the root user has no password or some default password set by the GRML developers. To fix this, passwd was run as user root and user grml (so that user wasn't using defaults as well), and the resulting shadow file was stored in "/home/sechome/.staticfs/etc/shadow". The sudoers file was truncated, and simple things were added such as /sbin/halt, /sbin/reboot, and
my-grml-x.
Contents: /home/sechome/.staticfs/etc/sudoers
grml ALL=NOPASSWD: /usr/bin/my-grml-x, /sbin/halt, /sbin/reboot
system-work creates a symbolic link for /usr/bin/my-grml-x to point to
my-grml-x.
The console screens need to be locked for physical access purposes. If the user were to lock the screen with xlock or similar, any Linux user with enough experience would know to check the other console windows to see if X was running from a console, terminate it, and have access to the system. Not only are all consoles completely open when GRML starts up, but they are also running as root, so this would be very bad.
To fix this, the following is added to "/home/sechome/.statichome/.zshrc" and "/home/sechome/.staticroot/.zshrc".
Snippet: /home/sechome/.statichome/.zshrc and /home/sechome/.staticroot/.zshrc
if [ "$TERM" = "linux" ]; then
[ "$UID" = "0" ] && su - grml
clear; vlock
fi
This executes a shell as user grml if the current user is root and we are working in a console. The new shell executes the same thing, which clears the screen and runs vlock. This locks the console down. For added security, both users execute this part of the code so that typing "exit" from the grml shell doesn't drop you to a root shell.
This file is a modified version of the "grml-x" file provided by GRML to start up the X server. Unfortunately, the "grml-x" script relies on sudo working on certain utilities without a password, and as described in
root User, this is no longer possible in my system. To fix this, the entire script is run as root, locations that previously were called using sudo were changed to regular commands, places that assumed user grml were changed, and then finally X is started using a su command to change to user grml before starting X.
Another change made was to make X start up without the TCP port 6000 open for remote connections. This shouldn't be a problem with X's security features, but since code would still be executed to deny a request, it's better to keep it closed if it isn't going to be used. An extra option ("-tcp") was added to allow X to start with the TCP port open since I do use it occasionally.
Also, because of the
Console Security features, X is executed in the background and the console is relocked using an alias to "my-grml-x".
Snippet: /home/sechome/.statichome/.zshrc
alias x="(sudo /usr/bin/my-grml-x ion3 &> /dev/null) &; disown; sleep 1; clear; vlock"
Patch: /home/sechome/grml/my-grml-x
--- grml-x 2008-03-14 17:04:11.000000000 -0500
+++ my-grml-x 2008-03-09 14:39:34.000000000 -0500
@@ -44,7 +44,7 @@
PROGRAMNAME=${0##*/}
HWINFO='/usr/sbin/hwinfo'
DATE=$(date)
- [ -n "$XINITRC" ] || XINITRC="$HOME/.xinitrc"
+ [ -n "$XINITRC" ] || XINITRC="/home/grml/.xinitrc" # bcable
# temporary files
HWINFO_TMP="/tmp/hwinfo.$$"
@@ -102,18 +102,19 @@
# }}}
# warn if running as user root {{{
- if [ -n "$ROOT" ] ; then
- if [ -r /etc/grml_cd ] ; then
- print "$bg[black]$fg[red]${bold_color}Warning: Please do not run grml-x as user root.${reset_color}"
- print "$bg[black]$fg[red]${bold_color}Running grml-x as user root is *not* supported!${reset_color}"
- print "$bg[black]$fg[red]${bold_color}Switch to user grml or run su - grml -c 'grml-x ...' instead.${reset_color}"
- print ''
- else
- print "$bg[black]$fg[red]${bold_color}Warning: Please do not run X.org as user root!${reset_color}"
- print "$bg[black]$fg[red]${bold_color}As soon as you have a working $XCONFIG please use startx instead of grml-x.${reset_color}"
- print ''
- fi
- fi
+# commented - bcable
+# if [ -n "$ROOT" ] ; then
+# if [ -r /etc/grml_cd ] ; then
+# print "$bg[black]$fg[red]${bold_color}Warning: Please do not run grml-x as user root.${reset_color}"
+# print "$bg[black]$fg[red]${bold_color}Running grml-x as user root is *not* supported!${reset_color}"
+# print "$bg[black]$fg[red]${bold_color}Switch to user grml or run su - grml -c 'grml-x ...' instead.${reset_color}"
+# print ''
+# else
+# print "$bg[black]$fg[red]${bold_color}Warning: Please do not run X.org as user root!${reset_color}"
+# print "$bg[black]$fg[red]${bold_color}As soon as you have a working $XCONFIG please use startx instead of grml-x.${reset_color}"
+# print ''
+# fi
+# fi
fstabuser=$(grep ':x:1000:' /etc/passwd)
fstabuser=${fstabuser%%[:]*}
# }}}
@@ -153,18 +154,21 @@
# writehwinfo {{{
writehwinfo()
{
- if [ -n "$ROOT" ] ; then
- su - $fstabuser -c "$HWINFO > $HWINFO_TMP"
- else
+ # bcable
+ #if [ -n "$ROOT" ] ; then
+ # su - $fstabuser -c "$HWINFO > $HWINFO_TMP"
+ #else
$HWINFO > $HWINFO_TMP
- fi
+ #fi
}
# }}}
# monitor {{{
monitor()
{
- sudo $HWINFO --monitor > $MONITORINFO
+ # bcable
+ $HWINFO --monitor > $MONITORINFO
+ #sudo $HWINFO --monitor > $MONITORINFO
}
# }}}
@@ -288,7 +292,9 @@
# mouse {{{
mouse()
{
- sudo $HWINFO --mouse > $MOUSEINFO
+ # bcable
+ $HWINFO --mouse > $MOUSEINFO
+ #sudo $HWINFO --mouse > $MOUSEINFO
# SynPS/2 Synaptics TouchPad
if grep -q 'Device:.*Synaptics' "$MOUSEINFO" ; then
@@ -457,7 +463,12 @@
nostart=o_nostart nodpms=o_nodpms nosynaptics=o_nosynaptics nousb=o_nousb \
nops2=o_nops2 genmouse=o_genmouse novref=o_novref nohsync=o_nohsync \
fallback=o_fallback usb=o_usb ps2=o_ps2 composite=o_composite \
- xinerama=o_xinerama
+ xinerama=o_xinerama tcp=o_tcp # bcable
+
+ # bcable
+ if [ -z "$o_tcp" ]; then
+ XOPTS="$XOPTS -nolisten tcp"
+ fi
if [[ $# == 0 || "$o_help" != "" || "$1" == '-h' || "$1" == '--help' ]]; then
usage
@@ -861,10 +872,15 @@
sed -i 's|InputDevice.*PS/2.*CorePointer|# & # deactivated to avoid two CorePointers|' $XCONFTMP
fi
fi
- [ -f $XCONFIG ] && sudo mv -f $XCONFIG $XCONFIG.old
- sudo mv $XCONFTMP $XCONFIG
- sudo chown root.root $XCONFIG
- sudo chmod 644 $XCONFIG
+ # bcable
+ [ -f $XCONFIG ] && mv -f $XCONFIG $XCONFIG.old
+ #[ -f $XCONFIG ] && sudo mv -f $XCONFIG $XCONFIG.old
+ mv $XCONFTMP $XCONFIG
+ #sudo mv $XCONFTMP $XCONFIG
+ chown root.root $XCONFIG
+ #sudo chown root.root $XCONFIG
+ chmod 644 $XCONFIG
+ #sudo chmod 644 $XCONFIG
}
# }}}
@@ -910,10 +926,12 @@
print ""
if [ -z "$DISPLAY" ] ; then
print "$bold_color$fg[green]Now trying to run startx.$reset_color"
- startx $XINITRC -- $XOPTS
+ su - grml -c "startx $XINITRC -- $XOPTS" # bcable
+ #startx $XINITRC -- $XOPTS
else
print "$bold_color$fg[green]Now trying to run startx on display $DISPLAY.$reset_color"
- startx $XINITRC -- :$DISPLAY $XOPTS
+ su - grml -c "startx $XINITRC -- :$DISPLAY $XOPTS" # bcable
+ #startx $XINITRC -- :$DISPLAY $XOPTS
fi
else
print "$bold_color$fg[blue]Not running startx as requested via option.$reset_color"
This system is quite awesome, but it is not perfect (no system is). There are a few known flaws with the security of the system, and most cannot be eliminated due to the design of the system. If you think of any more, or think of a plausible solution for any of these,
contact me.
Rebooting does not fix all problems associated with remote attacks. Any automated remote attacks would be completely eliminated by a reboot, but a skilled hacker that broke into this system, and got root access, could easily append commands to any of the startup scripts. An attacker could also remount the live-CD image as read-write ("mount -o remount,rw /live/image"), then modify everything. If that isn't enough, the attacker could create a new cramfs filesystem and throw it into
/home/sechome/addons/.
If someone were to physically gain access to a device with this system installed, such as a hard drive or USB drive, they could easily replace binary files with their own rootkits and other malware since the operating system is not encrypted. However, even with full encryption on the operating system partition, some sort of binary would need to be executed to decrypt that partition, so there will always be an issue with physical security.
It is for this reason that I suggest carrying around some sort of weapon to fight off evil ninjas and samurai that wish to steal your precious data.
Richard Stallman is already one step ahead of me here, though.
If a security flaw were to be discovered in a utility in the operating system used, it would be a pain to upgrade. For the most part, I just wait until the next version of GRML to upgrade my system, but a serious enough security flaw could be fixed by updated the cramfs filesystem in
/home/sechome/addons/.
I've also thought about writing a utility to automatically grab any security related packages from the GRML repositories and save them in a special directory under
/home/sechome/addons/ called "security". This directory could be cleared out every time GRML releases a new version, and the system would always be up to date.
These appendices are reference information for additional concepts that are unrelated to the overall scope of the system.
In order to easily generate a password-file and seed-file for
.ss, I developed a quick and easy system involving some hashing algorithms in order to generate a long password string easily from a smaller password.
These commands are used to generate these strings. The escaping inside of the arguments to "tr" are intended for zsh, so any other shell might need different escaping. Basically, there is no "\" in the actual character translation.
Command 1:
echo -n "PASS" | md5sum | tr "0-4a-c" "\!@#$%^&*"
Command 1 Output:
7^95&f9#6^!$$$f577!5^e^*!7^$6#^# -
This command takes the md5-sum of the password, then translates characters 0-4 with "!@#$%", and characters "abc" with "^&*". Because the range of outputs of the md5sum function is hexadecimal (0-9, a-f), this translation gives numerical, lowercase alphabetical, and special characters in its output.
Command 2:
echo -n "PASS" | sha1sum | tr "5-9d-fa-c" ")(*&^%\$#X-Z"
Command 2 Output:
Y%)(4%Y)%)ZZ3)&$Y0$3)23%3$03041*3^#230%) -
This command takes the sha1-sum of the password, then translates characters 5-9 with ")(*&^", the characters "def" with "%$#", and the characters "abc" with "XYZ". This creates numeric, uppercase alphabetical, and special characters in its output.
These two strings are then combined to form one longer string that contains a range from 0-9, "!@#$%^&*()", and "defXYZ".
From here, I memorized a few characters from the beginning and ending of each output. I will use this string as an integrity checker in the instance I have to regenerate these files. Sometimes when I'm bored or have nothing else to think about, I'll just start repeating this string in my head. I've done this so many times that I'll never forget this integrity string.
This could be better in terms of range (especially in alphabetical characters), but it represents all classes of characters to reduce direct brute force attempts to crack the password. so the resulting 26^72 password possibilities produces, according to Python, this many potential passwords or seeds:
7552331663217214825006745062553074726977155423512707515618786818627900161416446
34546410310899572146176
Both the seed-file and password-file must align perfectly in order to decrypt the data, so square that number to produce the number of possibilities, or:
5703771355123330237019007212917971463727350822126776738571796837795501025273128
0900988612121263585565441806450432685067156764815113982255928204809523985053041
9933797647200292755130496016995295694711422976
Version Info and Changelog
The document you are currently viewing is version 1.1.
20091123:
Version 1.4
- updated location of grml.sh
- updated grml.sh to erase itself so it doesn't get run twice by accident
- updated smount to modprobe for "aes" module instead of architecture specific "aes_i586"
- updated addons directory structure to have separate 64-bit and 32-bit packages
- updated addons to use squashfs instead of cramfs for faster speeds and bigger allotment for packages
- updated encbkup to exclude unnecessary files
- updated all scripts to support the 64-bit structure
- updated my-grml-x to work with newer GRML images
20090608:
Version 1.3
- updated my-grml-x to work with newest version of GRML (2009.05)
- updated the make-addons script to support commenting out lines with "#"
20080817:
Version 1.2
- created the script "make-addons" which generates the addon packages cramfs automatically
20080604:
Version 1.1
- better system for addon packages
20080316:
Version 1.0