SSD Advisory – GNU GRUB Command Injection
Find out how a vulnerability in GNU GRUB allows users on a Linux system to inject commands into the process of
grub-mkconfig which allows them to execute arbitrary commands with elevated privileges.
GRUB ships with a script that allows generating
/boot/grub/grub.cfg based on the operating systems installed on all the devices attached to the current system. The script is called
grub-mkconfig. On Debian and systems based on Debian
grub-mkconfig is run every time a kernel or driver is installed, upgraded or removed.
grub-mkconfig detects a GNU/Linux system installed on a different media device, it examines that system’s
/boot/grub/grub.cfg, looks at
menuentrys inside and generates new
menuentrys for the current system’s
grub.cfg based on that info. When a new
menuentry is being generated, certain GRUB commands (like
initrd) get copied from the “old” one.
grub-mkconfig doesn’t implement proper parsing of GRUB commands. When
grub-mkconfig copies GRUB commands, it copies the whole lines that start with those commands. Inserting a semicolon after certain GRUB commands allows injecting GRUB commands that
grub-mkconfig would not have copied otherwise.
An independent security researchers, NyankoSec, has reported this vulnerability to the SSD Secure Disclosure program.
The vendor has been informed and has released patches that were distributed across all affected distributions of Linux and other potentially affected OSes – more details are available here: https://lists.gnu.org/archive/html/grub-devel/2020-07/msg00034.html
grub-mkconfig detects GNU/Linux systems based on the presence of the following files:
ld.so. It can be placed at several different locations and can have various suffixes like
ld-linux.so.2, creating an empty
- A file named after a kernel mentioned in
/boot/grub/grub.cfg. For example:
/vmlinuz. This file can be empty.
grub-mkconfig detects operating systems on every partition, regardless of whether that partition is mounted or not.
grub-mkconfig detects operating systems on any kind of media: hard disks, SSDs, USD drives, SD cards, etc.
Potential exploitation methods
Being able to inject arbitrary GRUB commands is nice, but we can’t know beforehand what kernel and initrd our target is using.
We might assume that
/initrd.img are available, generate a
menuentry based on that and force its execution with
set default=$our_menuentry, but this approach is not robust.
The target system may have no
/initrd.img, maybe using a non-standard
AFAICT, it may also make circumventing full-disk encryption impossible in some cases. In general,this approach may break out target’s system, which is not something that we want.
It would be nice to be able to examine various
menuentrys at runtime and hijack their
linux commands. Unfortunately, GRUB script is not expressive enough to allow us to do that. To achieve that, we need a GRUB module.
Hijacking GRUB via module
To exploit the vulnerability in GRUB we will create a GRUB module called
ggh.mod is loaded, it registers a hook that fires up after GRUB has finished processing the entire
That hook goes through each
menuentry loaded by GRUB from the
grub.cfg file and replaces any
linux16 command with a hijacked version.
The hook also deletes any
menuentry that contains a certain magics tring (“ggh_442ecb7e12dc4b8e”). Our exploit generates two dummy entries with that kind of name.
The only drawback of this approach is that the target must keep the infected device attached to the system until it reboots.
Flow of Attack
A user having control over a device that is one of the above can place the files that will be processed by GRUB such that when the kernel (for example) is upgraded and grub is subsequently called to install itself – this GRUB module we created will get called and modify the
grub.cfg file with our controlled content.
Due to the complexity of the Exploit we will not be including it in this advisory, we are willing to share the Exploit with people that contact us via email.
These instructions have been tested on Debian 9 and 10. The same instructions should work on any new version of Ubuntu as well.
A GRUB module compiled on one distro will work with any other reasonably new distro or GRUB version.
sudo apt build-dep grub2
src/ggh_shellcode.1 to your liking or keep the default payload. Do not touch
src/ggh_shellcode.2 unless you know what you are doing. Also, make sure that
src/ggh_shellcode.1 is not too large: it gets base64-encoded and is passed as an argument to the Linux kernel, and Linux is not very happy about arguments over a certain size.
make. It will download the source code for GRUB (
apt source grub2), compile
ggh.mod and create
Find out the UUID of the device you want to infect. Try
findmnt -o TARGET,UUID or
Replace the dummy UUID (
build/rootfs/boot/grub/grub.cfg with the one you have just discovered.
Mount the device you want to infect and copy all the files in
build/rootfs to it:
cp -RT build/rootfs /path/to/your/device
Now you just need to wait for someone to install something that requires
grub-mkconfig to occur.