文章详情
GEEKPWN2020-云安全挑战赛决赛-baby_kernel题解
日期:2020/11/11 10:39:08
GEEKPWN2020-云安全挑战赛决赛-baby_kernel题解
前言
上周参加了酷炫的GEEKPWN大会,比赛时未能解出这道题目,因为是bpf相关的洞,之前也有一点了解,赛后七哥不厌其烦地给我指导,最终成功解出,非常感谢sunichi
师傅的帮助。本文相关文件在这里
漏洞挖掘
附件里贴心地给了source源码和linux-5.8.6的源码,我们拿beyond compare
比较一下两个项目文件夹,可以找到不同的文件,拿vscode比较一下具体地文件,即可看到diff
的结果.可以看到在verifier.c
文件中的scalar_min_max_add
函数中缺失了溢出检查。
具体看一下此处的代码和调用,只跟到check_alu_op
就差不多了,因为之前我们分析bpf漏洞的时候知道核心检查函数do_check
中会调用此函数。因此最后的漏洞调用链为:do_check
->check_alu_op
->adjust_reg_min_max_vals
->adjust_scalar_min_max_vals
->scalar_min_max_add
。
//verifier.c
static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
struct bpf_insn *insn,
struct bpf_reg_state *dst_reg,
struct bpf_reg_state src_reg)
{
switch (opcode) {
case BPF_ADD:
ret = sanitize_val_alu(env, insn);
if (ret < 0) {
verbose(env, "R%d tried to add from different pointers or scalars\n", dst);
return ret;
}
scalar32_min_max_add(dst_reg, &src_reg);
scalar_min_max_add(dst_reg, &src_reg);
dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
break;
//...
}
}
//
static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
struct bpf_insn *insn)
{
//...
return adjust_scalar_min_max_vals(env, insn, dst_reg, *src_reg);
}
//
/* check validity of 32-bit and 64-bit arithmetic operations */
static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
{
//...
else { /* all other ALU ops: and, sub, xor, add, ... */
if (BPF_SRC(insn->code) == BPF_X) {
if (insn->imm != 0 || insn->off != 0) {
verbose(env, "BPF_ALU uses reserved fields\n");
return -EINVAL;
}
/* check src1 operand */
err = check_reg_arg(env, insn->src_reg, SRC_OP);
if (err)
return err;
} else {
if (insn->src_reg != BPF_REG_0 || insn->off != 0) {
verbose(env, "BPF_ALU uses reserved fields\n");
return -EINVAL;
}
}
/* check src2 operand */
err = check_reg_arg(env, insn->dst_reg, SRC_OP);
if (err)
return err;
if ((opcode == BPF_MOD || opcode == BPF_DIV) &&
BPF_SRC(insn->code) == BPF_K && insn->imm == 0) {
verbose(env, "div by zero\n");
return -EINVAL;
}
if ((opcode == BPF_LSH || opcode == BPF_RSH ||
opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
if (insn->imm < 0 || insn->imm >= size) {
verbose(env, "invalid shift %d\n", insn->imm);
return -EINVAL;
}
}
/* check dest operand */
err = check_reg_arg(env, insn->dst_reg, DST_OP_NO_MARK);
if (err)
return err;
return adjust_reg_min_max_vals(env, insn);
}
}
上一文章:漏洞分析-Apple授权过程的任意账号登录漏洞($100,000)
下一文章:半途而废的测试(二)
相关推荐
- 05-21JE8u20反序列化利用链及序列化流构造技术分
- 11-09谈谈Django的RCE
- 10-20SEO赚钱技术和SEO赚钱思维
- 11-12记一次bc推广
- 11-17大数据-浅析Hadoop命令执行漏洞
- 10-21记录第二次“梅花三弄”的渗透之旅
- 05-25记一次艰难的溯源故事(对不起学长)
- 11-23从webpack开始发现的漏洞大礼包
- 05-31XCTF2021-Final-DubboWriteUp:SSRF-
- 10-21ctf中常见phprce绕过总结
- 05-24SOCasS(把SOC当作一种服务)的架构部署和技术
- 05-13JavaAgent从入门到内存马
- 10-21记一次某源码审计
- 05-18Xmind2020XSS漏洞导致命令执行复现