Introduction It’s that time of year again - the Binary Golf Grand Prix is back for a third year running! You can also check out my entries to the first and second times this amazing competition ran. The theme this year was to produce a binary that crashes a given program. Bonus points for hijacking execution, and submitting a patch to the project that fixes the vulnerability. Coinciding with the announcement of this year’s competition, @netspooky told me about a little-known accessory for the GameBoy/GameBoy Colour/GameBoy Advance called the Mobile Adapter GB, which let players connect their console to the internet via their mobile phone.
This year, @netspooky announced another round of the Binary Golf Grand Prix. If you missed it last year, the challenge was to create a palindromic binary - you can see the writeup of my entry, BootNoodle, here. This time around, the theme was polyglots, i.e. the challenge was to create a binary (as small as possible - hence the Golf part…) that was simulateously another filetype. The rules were laid out very clearly into 2 categories: first - the smallest file that satisfied all the rules wins; second - rack up points by overlapping more and more filetypes with the bytes of your host binary.
What’s Going On? Back in February 2020, there were some stirrings on the LKML about unexporting kallsyms_lookup_name() from the kernel. The main reason for this is that unscrupulous module developers will often simply add MODULE_LICENSE(‘GPL’) to their code (without actually licensing their module as such). Then, using kallsyms_lookup_name(), they can use any other exported kernel function to their heart’s content. The kernel developers don’t like this because it enables out-of-tree modules to call non-exported functions.
What’s In A Name? Back in August, the NSA and FBI jointly issued a Cybersecurity Advisory on a previously undisclosed piece of malware developed by the Russian GRU called “Drovorub” - a name that comes from the Russian words “дрово” and “руб”, which together translate to “woodcutter” or, as I’m taking it, “lumberjack”. What made this particular malware more interesting than usual is that it included a kernel module rootkit! In this post, I want to go through some of the techniques that this kernel module uses and how it relates to the techniques that we’ve already covered in other posts.
A few days ago, Google’s research team published an information leak vulnerability in the Linux bluetooth stack along with a very nice poc. In this post, I want to go through and dissect this poc to identify exactly what the vulnerability is and how it’s been fixed. This is the first kernel vulnerability that I’ve dove into deeply and I’ve found it to be surprisingly simple and straightforward. The vulnerability itself, dubbed Bleeding Tooth by Google, is able to leak values from the kernel’s stack memory.
Let’s see if we can hide the fact that a user is logged in! The idea is that we’ll be able to spawn a shell or login in as some user (we’ll choose root) and not have it show up in the output of tools like who or finger. Looking at the output of who, we see a list of all the active terminal devices and the users associated to them.
Most userspace system tools just parse and manipulate data from one or more files and present them nicely to STDOUT. We’ve already seen this with processes (see Part 7), but this time we’re going to do the same thing with open ports. By the end, we’ll be able to open a listener on port 8080 (any port would do) without it showing up in things like netstat. Assuming that a file is being read from, we need to try to find out which one.
Now that we know how to hide directories (see last time), we can also hide processes! This is because nearly all userspace tools that give us information about processes just read the contents of the /proc/ filesystem. We can check this by looking at the output of strace -e openat ps or strace -e openat top. So, if we hide directories with the name of the PID we want to keep secret, then these userspace tools won’t notice that the process is there!
In all the playing around I’ve been doing with Linux kernel modules, I decided to see what would happen if you tried to load one from a Docker container. It turns out that privileged containers (or just those with CAP_SYS_MODULE) are able to use the sys_init_module() and sys_finit_module() syscalls - which are what’s used to load kernel modules. As all containers share their kernel with the host (unlike VMs), this clearly results in yet another complete system compromise.
At this point, we’ve used several different techniques to manipulate the kernel into doing interesting things. We’re going to combine a few of these techniques now in order to hide certain files and directories from userspace. This post is probably the most intricate yet due to the fact that we have to manipulate the structure returned by the kernel to userspace. Roughly speaking, directory listing is handled by the syscall sys_getdents64 and its 32-bit counterpart sys_getdents (we’ll want to hook both, but they are identical except for a small addition in the 32-bit version).