Creating a Linux livecd

Update 2021-02-25: I found slides for a talk I did on this back in 2012-2013. See those slides here.

Part one: Why?

I use a Linux livecd frequently in my work.

  • Clonezilla is a useful tool to quickly back up data. I use it on client machines before I do something potentially destructive, or before a reimage, to make sure that I can’t forget something (as I have done before trying to manually copy important data off the old disk).
  • Knoppix is of course very useful in that it’s a whole environment. It has imaging tools, can read documents, browse the web, etc.
  • Backtrack has been very useful when I attend cons, and when I worked the InfoSec Southwest Demolition Derby CTF.
  • Offline NT Password and Registry editor is tiny (fits on a floppy, even) and resets Windows passwords.

However, there is a huge, crippling problem with every single livecd out there.

They all ship with caps lock as caps lock by default.

Fuck.

That.

Shit.

And, though that is obviously the worst problem with livecds, there are others. (God does alias l=ls instead of alias l=less annoy me.) If I’m going to build my own livecd anyway, I might as well include a decent screenrc/bashrc/profile/inputrc, and actually install

  • Include dhd, my “distributed home directory” git repository that contains dotfiles and the like. Never have to remember ls -Flarth (sort by mtime, ascending) again!
  • Include stumpwm, the lovechild of GNU Screen and GNU Emacs. (stumpwm is a really nice “X multiplexer”, if you want your X session to be a lot like a screen session. I tried using it as my main desktop manager for a while and decided it was a little too restrictive - sometimes I do want to move a window with my mouse, dammit! - but for a computer that I’m trying to fix, rather than do all of my work from, it’s perfect.
  • Include conkeror, the web browser that got Emacs disease. (Unlike stumpwm, I do use conkeror every day, but like stumpwm, I don’t switch over to it completely, but instead use it alongside other browsers.)
  • Include Emacs. Obviously
  • Include X, but don’t start it by default.

And since this is a totally custom livecd, I could also do pretty interesting things like

  • Include a recent ~/.ssh/known_hosts file. Actually, I decided to start keeping this inside my dhd repository that I’m including anyway, so every machine I use can have a synced-up copy. (Except Windows, because PuTTY uses the registry for this shit, ugh.) Note: if you publish your known_hosts file, whether on the web, in git, or on a livecd that might find its way outside of your control, you should consider turning on hashing (discussed in ssh_config(5) or on the internets); this is turned on by default on new versions of OpenSSH.
  • Include the certificate of my own SSL certificate authority which I use for non-customer stuff.

Part two: Selecting the tools

I have tried several methods for creating a Linux livecd, and found several with downsides. I eventually settled on Debian Live under a dedicated Debian Wheezy (currently “testing”, and will be released as 7.x). (I couldn’t make it work under Ubuntu, which is my normal distribution.)

Here are some notes about my somewhat frustrating selection process.

  • I investigated rebuilding Knoppix, but initial investigation seemed to indicate that you must have Knoppix installed to your hard drive, which I wanted to avoid if possible.
  • I saw the same requirement for customizing SystemRescueCd, which is another livecd I’ve found use for in the past.
  • Next I tried this page on the Ubuntu wiki: LiveCDCustomizationFromScratch. It looked promising. However:
    • I had a problem causing a kernel panic on a system with mdadm-configured disks. Bug report.
  • I later tried Debian Live, using a 3.x package installed from Ubuntu 11.08 (Oneiric).
    • I had a problem where the live.cfg that was generator for isolinux would not contain the proper name for the kernel on the disk. Bug report.
    • Since upgrading from Oneiric to Precise in April, I have not revisited this.
  • I tried the Casper scripts (from Ubuntu’s LiveCDCustomizationFromScratch page) under Precise, when it came out, but even when starting totally from scratch (no customizations at all), it just panics on boot.
  • I decided to try to use Debian Live from Debian itself. I installed Wheezey (testing / what is going to be 7.x when it is officially release) and used the Debian-Live in APT (again the unstable 3.x distribution), and it worked! This does have the downside of requiring a dedicated build machine (actually a virtual machine) for my livecd, but unlike a dedicate Knoppix build machine, this one is easily updatable, and so forth.

I heard about, but didn’t get around to, these methods:

  • grml-live is strange because it relies on the AIK which relies on (a customized version of) Debian Live, so you end up having to know a little about D-L, AIK, and grml.
  • Gentoo’s catalyst sounds interesting, and I like Gentoo OK and all, but the thought of a Gentoo VM compiling packages all day on my already old and overloaded VM server just didn’t sound like much fun. It takes long enough just unpacking debian pacakges already on my disk, if I was recompiling them all the time it’d probably take half the day to do one test build.
  • I haven’t tried the Debian Live package in Ubuntu Precise, only Oneiric. I do note that there is an important difference between Ubuntu and Debian - Ubuntu uses Upstart, and Debian uses sysvinit. This is relevant because live depends on the live-config-backend virtual package which resolves to one of live-config-{systemd,sysvinit,upstart, and that package relies on systemd, sysvinit, or upstart being installed on the host system.

Part three: Working with Debian Live

  • D-L has some sorta-OK documentation on its homepage. Well… it did. When I was using it, you could get documentation for 1.x (“oldstable”), 2.x (“stable”), or 3.x (“testing”) at http://live-manual.debian.net; now, that server refuses HTTP requests. Even when I was using it, the 1.x and 2.x documentation had a bad CSS link (though 3.x worked). All in all, it’s best to install the live-manual-all package on Debian or Ubuntu so you can get a decent copy of the documentation.
  • This documentation is useful for simple customizations. If you want to replace files in the livecd filesystem, for example, this is easy. It’s also pretty short - you can read through the whole thing in 20 minutes or less.

Here’s a straight walkthrough to get to what I’m using (with sensitive bits removed).

  • run mkdir livecd; cd livecd; lb config to create initial directory structure

  • Modify the auto/config script. You specify basic settings here like livecd username, lists of packages to install, local mirrors, etc.

    • One change I made from the default was to by default run the kernel with console= parameters that specify both the keyboard/monitor and the first serial port as the console. Very nice if you’re used to serial ports. Of course, this requires that the machine be configured to boot from cd by default, but still, it’s pretty handy.
  • Add a list of packages inside a file like config/package-lists/list.chroot (it must end in .chroot if it is to be installed inside the livecd filesystem). These Debian packages will be installed and usable when you boot your livecd.

  • If you want to modify the isolinux configuration, add files to config/includes.binary/isolinux. For example, to a custom splashscreen, create a splash.png file in that directory.

  • Add stuff to config/includes.chroot that you want to be part of the livecd’s filesystem.

  • I create some dedicate livecd ssh keys and put them inside config/includes.chroot/etc/ssh containing sshd_host_*_key{,.pub} files, so that I can ssh albacore and be relatively sure that I’m not being MITM’d. D-L removes ssh keys by default, so if you want to do this you have to remove the file /usr/share/live/build/hooks/006-remove-openssh-server-host-keys.chroot on the host system. (I renamed it to *.disabled and that works too.)

  • Make changes to live-config scripts in config/includes.chroot/lib/live/config

    • First, install the live-config package on the host

    • Then copy all the files in /lib/live/config inside the chroot.

    • Then make these changes

        mkdir -p config/includes.chroot/lib/live/config
        # cp /lib/live/config/* config/config/includes.chroot/lib/live/config
        # you could copy the whole directory there, but since we only want to zero out
        # some files, I'm just going to do that like this:
        cd config/includes.chroot/lib/live/config
        for file in 006-gdm 007-gdm3  008-kdm 009-lxdm 010-nodm 011-slim 012-xinit \
            102-gnome-panel-data 103-gnome-power-manager 104-gnome-screensaver \
            107-kde-services 117-xserver-xorg 111-sslcert 002-user-setup
        do
            echo -n "" > $file
        done
      
    • All that does is copy completely blank files over some of the default live-config scripts, so it will:

      • speed up boot time by not autogenerating an ssl certificate
      • disable the gnome and kde services I don’t care about anyway
      • disable X from starting at boot (you can still run startx though)
      • disable live user creation entirely (I do it myself in an rc script instead)
  • Add your certificate authority to config/includes.chroot/usr/local/share/ca-certificates. Any certs in this directory are automatically added to the trusted store by update-ca-certificates (see the man page for more info).

  • Create a default/keyboard file to make capslock be control. This is useful because it works in the console, not just X!

  • To create my user, I did this:

    • I called my user “jessica”.
    • Added an /etc/skel-jessica directory.
      • Almost all of what’s in here is symlinks to stuff in the dhd directory… see dhd/hbase for the type of stuff I keep there.
      • (I was having some permissions problems when creating /home/jessica directly, even when doing a subsequent chown -R. Adding a different skel directory and using it in the user creation hook solved that problem.)
    • Added a users.chroot hook. This adds the user and group using my skel directory, and lets the user sudo without typing its password.
    • It also does a clone of my dhd git repository in the user’s homedir. This is a more ghetto way of doing a git submodule, which is probably a better solution. Note that this clone is done at livecd build time and therefore I have a single version of my dhd repo baked in to the disc.
    • This script also sets the live user’s password with useradd’s --password option. This option accepts an encrypted password that you can generate like this echo password | mkpasswd --method=sha-512 --stdin

Part four: checking the configuration into git.

  • You’ll want a .gitignore file that excludes the temporary stuff that lb creates.
  • Git doesn’t store full permissions, only the executable bit. This is a problem because of the stuff that goes into includes.chroot - if you have umask as 077 like I do, when you check out the git repo, all files will prohibit group and other from reading them, which causes a headache in lots of the things in the chroot.
    • I have a setperms.sh script which does this, which I run before doing the build at all.
    • I also have a doit.sh script which runs that command, and sets up a build log with tee and ghetto log rotation.

Part five: Misc

  • I have a config/hooks/disabled-services.chroot which disables services I dont' want to run at boot time. It’s useful to have nfs installed in case I need it, but there’s no reason to have e.g. portmapper start when you boot - it’s more secure, plus it will boot faster without it.
  • I have a config/includes.chroot/etc/rc.local which runs this line: su jessica -c 'bash ${HOME}/.rc.user' &, where jessica is my livecd user I created earlier. I can add any command I want inside ~jessica/.rc.user, and it is run at boot time. I use this to update my dhd git repository at boot time so that I always have the latest bashrc.

Part six: Security

There are some things I do that should give you cause for concern. Here’s a list of concerns and my reasoning for doing what I did.

  • Bake in a user’s password, so that anyone who gets a copy of the livecd can get it and crack it.
    • This saves me trouble - I can just boot from the cd and walk away, and later ssh into the machine because I already know the password.
    • I give a good passphrase for my user, not a simple password. It’s easier to type ~20 characters than drive to a client’s site because I forgot to fucking run passwd before leaving.
    • For this fact to be of any use to an attacker, they’d have to be interested in targetting the system that I boot from. On the one hand, this is not controlled by me (I don’t break the systems, I just fix them), but on the other hand, if the attacker can break it so bad that it has to be solved from a livecd, they don’t need a livecd to compromise it.
    • Furthermore, for this to be useful to an attacker, they’d have to know when the livecd is booted, and be on its local network. Because this changes so often, it is unlikely, though possible.
  • Bake in the host ssh keys
    • This is honestly of more concern to me than exposing the hash of a good password.
    • It still requires an attacker to specifically target the system I’m working on, and prepare to MITM me in advance
    • I believe that this is less likely to compromise me than generating new ssh keys on each boot and ignoring the security check when sshing to the livecd (come on, we’ve all done it). On the other hand, if it goes unnoticed, the results may be more damaging.

Possible security solution - full disc encryption

I really want to completely encrypt the livecd filesystem. This is possible - old versions (2.x) of debian-live supported the --encryption switch, but the 3.x version removed it. I think that TAILS may have done some work in this area?

This would solve my main security problems:

  • My password hash can’t be compromised until the filesystem is decrypted. This is unlikely but still possible.
  • My ssh host private keys can’t be compromised. This is a far bigger concern because they’re just sitting unencrypted in side the livecd’s filesystem.squashfs file.

Other security stuff

  • I can configure xscreensaver to lock the screen after a certain period of time by default.
  • I can prevent autologin somehow (maybe with the user-setup package thing?)

Tangents

Interesting shit I discovered while writing this post:

Addendum - adding third party repositories

Of course, APT supports third party repositories. The documented Debian Live way to do this, however, won’t work for us.

Debian Live lets you add a repository line to the config/archives/live.list.{binary,chroot} files in order to add the repository to the livecd system and the chroot respectively. (I don’t really understnad this distinction well, but it doesn’t matter because we can’t really use this anyway.) Almost all apt repositories have their packages signed by a GPG key, however, Debian Live provides no way to add a key to the trusted list.

All I do is create a hook that adds the repository manually and then installs the packages I want from it.

An example, config/hooks/drbl-apt-repository-gpg.chroot:

slist=/etc/apt/sources.list.d/albacore.list
rm $slist
touch $slist
packages=""

## DRBL repository, contains Clonezilla
# NOTE: you could replace 'testing' with 'stable' or 'unstable' if you like:
echo "deb http://free.nchc.org.tw/drbl-core drbl testing" >> $slist
gpg --keyserver keys.gnupg.net --recv 40009511D7E8DF3A
gpg --export 40009511D7E8DF3A | sudo apt-key add -
packages="${packages} clonezilla"

## Add other repositories here:
echo "deb http://deb.torproject.org/torproject.org sid main" >> $slist
gpg --keyserver keys.gnupg.net --recv 886DDD89
gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add -
packages="${packages} deb.torproject.org-keyring tor tor-geoipdb torsocks"

apt-get update
apt-get install --yes $packages

Almost all apt repositories are signed by GPG keys.

  • After the normal packages have been installed, add the repository to /etc/apt/sources.list inside the chroot
  • Get the GPG key that signs packages from the new repo
  • Add

One of the reasons I wanted to do this was to replace the seperate Clonezilla livecd with this one. I had thought that the clonezilla packages was installed from my package list, but it turns out that it’s not in Debian at all. You need to add this repository to the chroot’s sources.list.

  • To add the repository to the chroot’s sources.list, add this line to config/archives/drbl.list.chroot (You could also choose stable or unstable rather than testing):
  • You should also add it to the livecd’s sources.list by adding the same line to config/archives/live.list.binary.
  • Importing the GPG key requires a chroot hook. Add the following to config/hooks/drbl-apt-repository-gpg.chroot: