TL;DR
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.
Vulnerability Summary
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.
When grub-mkconfig
detects a GNU/Linux system installed on a different media device, it examines that system’s /boot/grub/grub.cfg
, looks at menuentry
s inside and generates new menuentry
s for the current system’s grub.cfg
based on that info. When a new menuentry
is being generated, certain GRUB commands (like linux
and 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.
CVE
CVE-PENDING
Credit
An independent security researchers, NyankoSec, has reported this vulnerability to the SSD Secure Disclosure program.
Vendor Response
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
Vulnerability Analysis
Basic details
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 likeld-linux.so.2
, creating an empty/lib/ld.so
is enough./boot/grub/grub.cfg
- 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 /vmlinuz
and /initrd.img
are available, generate a menuentry
based on that and force its execution with settimeout=0
and set default=$our_menuentry
, but this approach is not robust.
The target system may have no /vmlinuz
or /initrd.img
, maybe using a non-standard init
, etc.
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 menuentry
s 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
.
When ggh.mod
is loaded, it registers a hook that fires up after GRUB has finished processing the entire grub.cfg
file.
That hook goes through each menuentry
loaded by GRUB from the grub.cfg
file and replaces any linux
or 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.
Exploit Compiling
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
Edit 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.
Run make
. It will download the source code for GRUB (apt source grub2
), compile ggh.mod
and create build/rootfs
.
Find out the UUID of the device you want to infect. Try findmnt -o TARGET,UUID
or blkid
.
Replace the dummy UUID (00000000-0000-0000-0000-000000000000
) in 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 upgrade-grub
/ grub-mkconfig
to occur.