Get root on Linux: learn the secret password

A pair of Spanish security researchers just revealed a groanworthy get-root-on-Linux bug.

Strictly speaking, just in case we needlessly provoke the ire of Linux fans out there, it’s not a Linux bug (or even more strictly, a GNU/Linux bug), because the problem is in one of the startup scripts used in many popular distributions, rather than in the kernel or the core utilities.

It’s also, if we’re honest, not a particularly dangerous bug, if indeed it is a bug at all, because you can typically only exploit it if:

  • You have physical access to the computer.
  • The system partition (and probably the rest of the computer, too) is encrypted.
  • You deliberately get the decryption password wrong.

When you trigger the bug, you end up in a very stripped-down root shell with access to the /boot partition only.

If you’re breaking into someone else’s unattended laptop, that’s not such a big deal because you could almost certainly get much further simply by booting off one of those cool USB flash drives that all sysadmins have in their pockets at all times.

And if you’re trying to get root on some sort of internet kiosk where the keyboard and screen are visible but everything else is tucked away behind a padlock, the hard disk probably hasn’t been protected using full disk encryption, which means that this vulnerability isn’t exposed.

The reason full disk crypto has to be enabled is that this password bypass bug, rather embarrassingly…

…is in the script that asks you to enter your hard disk password.

It turns out that all you have to do is enter the wrong password close to 100 times, and that’s that.

In fact, you can just press [Enter] and hold it down so it starts autorepeating, and after about a minute you suddenly drop into a recovery shell.

The coding error is an interesting one, and teaches us a good lesson: when you get an error back from someone further down the chain, it really matters why the error happened, not merely that it did.

As the researchers noted in their article explaining the bug, the password validation function goes something like this, expressed in pseudocode:

function dounlock: 
   for tries = 1,3 do
      read password
      apply password to drive 
      if drive is unlocked then return OK end
   end
   return ERROR
end

So far, so good.

You’re probably expecting that the dounlock function is used something like this:

function tryunlock:
   for tries = 1,5 do
      if dounlock is OK then return OK end
      wait a while
   end
   # User didn't know the password.
   # Start from the top after a bigger delay.
   reboot computer 
end

But that’s not what happens.

Further up the chain is a function something like this:

function dostartup:
   for tries = 1,30 do
      . . .
      try dounlock
      # If the root device hasn't shown up yet, give it a little while
      # to allow for asynchronous device discovery (e.g. USB).
      wait a while
      if root device is unlocked then return OK end
   end
   drop to emergency root shell
end

As you can see, there are two commingled problems here:

  • The dounlock function gives three guesses, but is allowed to run 30 times.
  • When the 30 tries are exhausted, the reason why the root device ended up unlocked gets ignored.

In other words, by the time the incorrect password guessing is over, the startup scripts don’t take into account that you didn’t know the password.

Of course, this may be deliberate, given that the root shell appears on the local computer, and therefore requires physical access.

Remember that the bulk of the hard disk remains encrypted, so a crook can’t easily access your data this way.

Nevertheless, Ubuntu-based distros load the above disk unlocking scripts from a special unencrypted partition called /boot, which contains unencrypted copies of your kernel and, of course, the offending startup scripts.

So, giving crooks and miscreants an easy way to access a root prompt, even if they can’t get at the USB ports to add or extract additional data, makes it correspondingly easy for them to subvert the bootup process itself.

That means they might fairly easily and unobtrusively be able to add a few lines to log your hard disk password next time you start up.

And, anyway, what more embarrassing way to give away a root shell than by simply allowing a “hacker” to press [Enter] a lot?

What to do?

The distros that use the offending script (we tried ElementaryOS, which is built on a Debian/Ubuntu core) may well decide that this code is worth changing, so watch your distro’s mailing list.

On the other hand, the various distro maintainers might also decide that dropping to an emergency shell ought to be the default behaviour when the root filing system won’t mount, regardless of why.

If this worries you, we have two suggestions.

A quick workaround suggested by the authors of the paper is to add the kernel boot parameter panic=10, which means that the kernel will automatically reboot after 10 seconds if the system panics (the Linux equivalent of a Windows Blue Screen or a macOS Dark Grey Screen of Death).

That works here because the startup script above actually implements the “drop to emergency root shell” part like this:

if kernel parameter panic is set then
   wait (panic) seconds
   reboot
else
   drop to emergency root shell
end

If you have an internet kiosk, for example, you probably already have autorebooting enabled, so you probably already bypass the unwanted root shell.

A better workaround, but admittedly a much more complex one, is to configure your Linux bootloader to unlock your hard disk earlier in the boot process. (The bootloader on Ubuntu-based systems is usually GRUB, which supports this feature.)

This bypasses the buggy script above, because the root device is already unlocked before the script runs.

This also allows you to have /boot encrypted as well, making it harder for a crook with limited access and fiddling time to booby-trap your computer by modifying the kernel or your startup scripts.

Unfortunately, most distros don’t have an install-time feature to encrypt everything including /boot, and the procedure for doing so varies from distro to distro, so we can’t give you a simple list of instructions here.

Of course, you could just switch to macOS, where all this stuff is taken care of for you at install time…

…but we know what would happen if we were to make a suggestion like that.