diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..426ddb0 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +obj-m += drv.o + +CC=gcc +ccflags-y += "-g" +ccflags-y += "-O0" + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + # compile the trigger + $(CC) trigger.c -O2 -o trigger + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + rm -fr ./trigger diff --git a/README.md b/README.md index a96cc37..3947d34 100644 --- a/README.md +++ b/README.md @@ -1 +1,15 @@ -# kernel_rop \ No newline at end of file +# Linux Kernl ROP demo + +This is a vulnerable Linux kernel driver used to demonstrate in-kernel +privilege escalation ROP (Return Oriented Programming) chain in practice. The +article URL for Part 1 is available at +. + +The driver module is vulnerable to OOB access and allows arbitrary code +execution. An arbitrary offset can be passed from user space via the provided +ioctl(). This offset is then used as the index for the 'ops' array to obtain +the function address to be executed. + +* drv.c - vulnerable kernel driver +* trigger.c - user-space application to trigger the OOB access via the provided + ioctl diff --git a/drv.c b/drv.c new file mode 100644 index 0000000..c87abee --- /dev/null +++ b/drv.c @@ -0,0 +1,90 @@ +/** + * Vulnerable kernel driver + * + * This module is vulnerable to OOB access and allows arbitrary code + * execution. + * An arbitrary offset can be passed from user space via the provided ioctl(). + * This offset is then used as an index for the 'ops' array to obtain the + * function address to be executed. + * + * + * Full article: https://cyseclabs.com/page?n=17012016 + * + * Author: Vitaly Nikolenko + * Email: vnik@cyseclabs.com + **/ + +#include +#include +#include +#include +#include "drv.h" + +#define DEVICE_NAME "vulndrv" +#define DEVICE_PATH "/dev/vulndrv" + +static int device_open(struct inode *, struct file *); +static long device_ioctl(struct file *, unsigned int, unsigned long); +static int device_release(struct inode *, struct file *f); + +static struct class *class; +unsigned long *ops[3]; +static int major_no; + +static struct file_operations fops = { + .open = device_open, + .release = device_release, + .unlocked_ioctl = device_ioctl +}; + + +static int device_release(struct inode *i, struct file *f) { + printk(KERN_INFO "device released!\n"); + return 0; +} + +static int device_open(struct inode *i, struct file *f) { + printk(KERN_INFO "device opened!\n"); + return 0; +} + +static long device_ioctl(struct file *file, unsigned int cmd, unsigned long args) { + struct drv_req *req; + void (*fn)(void); + + switch(cmd) { + case 0: + req = (struct drv_req *)args; + printk(KERN_INFO "size = %lx\n", req->offset); + printk(KERN_INFO "fn is at %p\n", &ops[req->offset]); + fn = &ops[req->offset]; + fn(); + break; + default: + break; + } + + return 0; +} + +static int m_init(void) { + printk(KERN_INFO "addr(ops) = %p\n", &ops); + major_no = register_chrdev(0, DEVICE_NAME, &fops); + class = class_create(THIS_MODULE, DEVICE_NAME); + device_create(class, NULL, MKDEV(major_no, 0), NULL, DEVICE_NAME); + + return 0; +} + +static void m_exit(void) { + device_destroy(class, MKDEV(major_no, 0)); + class_unregister(class); + class_destroy(class); + unregister_chrdev(major_no, DEVICE_NAME); + printk(KERN_INFO "Driver unloaded\n"); +} + +module_init(m_init); +module_exit(m_exit); + +MODULE_LICENSE("GPL"); diff --git a/drv.h b/drv.h new file mode 100644 index 0000000..823a48f --- /dev/null +++ b/drv.h @@ -0,0 +1,3 @@ +struct drv_req { + unsigned long offset; +}; diff --git a/trigger.c b/trigger.c new file mode 100644 index 0000000..1327cb1 --- /dev/null +++ b/trigger.c @@ -0,0 +1,40 @@ +/** + * User-space trigger application for OOB in drv.c + * + * + * Full article: https://cyseclabs.com/page?n=17012016 + * + * Author: Vitaly Nikolenko + * Email: vnik@cyseclabs.com + * + **/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "drv.h" + +#define DEVICE_PATH "/dev/vulndrv" + +int main(int argc, char **argv) { + int fd; + struct drv_req req; + + req.offset = atoll(argv[1]); + + //map = mmap((void *)..., ..., 3, 0x32, 0, 0); + + fd = open(DEVICE_PATH, O_RDONLY); + + if (fd == -1) { + perror("open"); + } + + ioctl(fd, 0, &req); + + return 0; +}