首页 > 其他分享 >CVE-2022-2588 学习记录

CVE-2022-2588 学习记录

时间:2023-02-07 18:55:45浏览次数:61  
标签:struct double free 2588 filter tcfa 2022 CVE route4

  • 简介

    netlink 协议 中的 CLS_ROUTE4 模块中存在 double free。

    影响范围:linux 5.19 之前

    利用条件:linux 用户有 CAP_NET_ADMIN 权限

    内核编译选项:

    //下面三个可以触发 poc
    CONFIG_NET_CLS_ROUTE4=y
    CONFIG_DUMMY=y        // 或使用的其他设备
    CONFIG_NET_SCH_QFQ=y  // 或使用的其他设备
    // 跑 exp 还需要,并且 qemu 内存得大
    CONFIG_NET_CLS_BASIC=y
    
  • 漏洞分析

    漏洞触发点位于 route4_change 中,会生成并初始化一个 route4_filter 结构,如果存在相同 handle 的 route4_filter,则会申请新的释放旧的:

    申请新的 route4,fold 指向已经存在的 route4_filter,然后通过 route4_set_parms 更新 handle。

    image-20230205173347188

    如果新老 handle 不同,则会删除并释放之前的 handle,最后执行的释放函数是 route4_delete_filter_work。

    image-20230205174531216

    注意到这里的判断条件是不一样的:将旧的 route_filter 从列表中删除要求 handle 不为 0:

    image-20230205174830400

    而释放旧的 route_filter 只需要判断 fold 存在即可:

    image-20230205174907826

    这样的话可以构造 handle 为 0 的 route4_filter,释放后的 route4_filter 还会在链表中,就可以实现 double free 了。

    在 route4_delete_filter_work 中调用 route4_destroy 释放内存,

    image-20230205194427320

    释放的结构为 route4_filter:

    struct route4_filter {//大小 144
    	struct route4_filter __rcu	*next;
    	u32			id;
    	int			iif;
    
    	struct tcf_result	res;
    	struct tcf_exts		exts;
    	u32			handle;
    	struct route4_bucket	*bkt;
    	struct tcf_proto	*tp;
    	struct rcu_work		rwork;
    };
    

    然后在 route4_delete 函数中也会调用 route4_delete_filter_work 任务,所有也可以用 route4_delete 功能实现 double free。

    image-20230205194923352

    image-20230205194945636

    除了 route4_filter 结构,在 tcf 初始化的时候还会申请一个 f->exts->action 的空间:

    static inline int tcf_exts_init(struct tcf_exts *exts, struct net *net,
    				int action, int police)
    {
    	··· ···
    	exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), //这里申请32个指针类型共256字节
    				GFP_KERNEL);
    	··· ···
    }
    
    struct tc_action {//大小192
    	const struct tc_action_ops	*ops;
    	__u32				type; /* for backward compat(TCA_OLD_COMPAT) */
    	struct tcf_idrinfo		*idrinfo;
    
    	u32				tcfa_index;
    	refcount_t			tcfa_refcnt;
    	atomic_t			tcfa_bindcnt;
    	int				tcfa_action;
    	struct tcf_t			tcfa_tm;
    	struct gnet_stats_basic_packed	tcfa_bstats;
    	struct gnet_stats_basic_packed	tcfa_bstats_hw;
    	struct gnet_stats_queue		tcfa_qstats;
    	struct net_rate_estimator __rcu *tcfa_rate_est;
    	spinlock_t			tcfa_lock;
    	struct gnet_stats_basic_cpu __percpu *cpu_bstats;
    	struct gnet_stats_basic_cpu __percpu *cpu_bstats_hw;
    	struct gnet_stats_queue __percpu *cpu_qstats;
    	struct tc_cookie	__rcu *act_cookie;
    	struct tcf_chain	__rcu *goto_chain;
    	u32			tcfa_flags;
    	u8			hw_stats;
    	u8			used_hw_stats;
    	bool			used_hw_stats_valid;
    }; // 但参与释放的 tc_action 不是结构体本身,而是 32 个结构体指针的空间,共 256 字节
    
  • 漏洞利用

    使用了 Dirty Cred 方法。

    这里可以 double free 的两个结构,一个是 kmalloc-192 的 route4_filter,另一个是一个指针数组空间,大小属于 kmalloc-256。struct file 大小为 232,可以利用 256 的 chunk 进行 double free,让两个文件描述符指向同一个 struct file。

    cross cache attack

    struct file 的结构体申请内存由 kmem_cache_zalloc 实现,使用的 slab 是 filp_cache。

    cross cache attack 的思路是:当一个 slab 页面全部被释放的时候会进行回收,这时被回收的页面是可以被其他种类的 slab 使用从而实现绕过 slab 种类的限制。

    image-20230205221517696

    1. 首先堆喷该大小的堆块,然后 double free 目标的指针指向其中一个,然后 free(第一次 free)。
    2. 将喷射的这些堆块都 free 掉,那么 double free 掉的堆块所在的 slab 页面中所有的堆块大概率都会被释放掉,该 slab 页面为空然后被系统回收。
    3. 喷射其他类型的 slab 堆块(filp等),让这个 slab 页面被其他类型的 slab 申请到,而此时 double free 目标的指针仍然指向其中的一个 struct。
    4. 此时进行第二次 free,成功实现不同种类 slab 的 double free。

    流程图:

    image-20230205223750375

    文件写入

    写入一个文件需要顺序执行:

    1. 文件权限检查
    2. 写入数据

    那么可以通过在这两个步骤之间进行竞争,在中间对 struct file 进行替换,将具体写入操作写到无写权限的文件之中,更细节的处理见 Dirty Cred 的分析。

  • 参考文献

标签:struct,double,free,2588,filter,tcfa,2022,CVE,route4
From: https://www.cnblogs.com/m00nflower/p/17099486.html

相关文章