服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

Linux内核cls_route过滤器UAF漏洞(CVE-2022-2588)分析与验证

日期: 来源:ADLab收集编辑:启明星辰

更多安全资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn)












一、前 言


数月前,国外安全组织ZDI研究人员披露了一个Linux内核本地权限提升漏洞,该漏洞出现在流量控制子系统包分类器的cls_route过滤器中,当旧过滤器句柄为0时,在释放之前内核不会从哈希表中将其删除,其漏洞编号为CVE-2022-2588,而且还提出了一种新的漏洞利用方法,命名为DirtyCred,该方法可绕过广泛采用的内核保护和漏洞利用缓解措施,从而实现权限提升。


二、Rtnetlink简述与实现简析


2.1 Rtnetlink简述
Rtnetlink是所有内核网络子系统使用的网络连接总线,包括网络接口、路由、fdb和邻居。一些内核网络子系统也在通用netlink总线上提供服务。Linux内核网络子系统使用消息类型和系列向Rtnetlink内核注册处理程序。Rtnetlink允许读取和更改内核的路由表。它在内核中用于在各种子系统之间进行通信,也用于与用户空间程序进行通信。网络路由、IP地址、链接参数、邻居设置、排队规则、流量类别和数据包分类器都可以通过NETLINK_ROUTE套接字进行控制。Rtnetlink由以下消息类型组成(除了标准的netlink消息):
  • RTM_NEWLINK、RTM_DELLINK、RTM_GETLINK创建、删除或获取有关特定网络接口的信息。

  • RTM_NEWADDR、RTM_DELADDR、RTM_GETADDR添加、删除或接收有关与接口关联的IP地址的信息。

  • RTM_NEWROUTE、RTM_DELROUTE、RTM_GETROUTE创建、删除或接收有关网络路由的信息。

  • RTM_NEWNEIGH、RTM_DELNEIGH、RTM_GETNEIGH添加、删除或接收有关邻居表条目的信息(例如,ARP条目)。

  • RTM_NEWRULE、RTM_DELRULE、RTM_GETRULE添加、删除或检索路由规则。

  • RTM_NEWQDISC、RTM_DELQDISC、RTM_GETQDISC添加、删除或获取排队规则。

  • RTM_NEWTCLASS、RTM_DELTCLASS、RTM_GETTCLASS添加、删除或获取流量类别。

  • RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER添加、删除或接收有关流量过滤器的信息。

2.2 实现简析
当内核启动加载,在初始化netlink协议实现时,会调用rtnetlink_init()函数初始化路由netlink socket接口,该函数实现如下:
根据代码可知,通过rtnl_register()函数将不同的消息类型和对应操作进行绑定,该函数签名为void rtnl_register(int protocol, int msgtype,rtnl_doit_func doit, rtnl_dumpit_func dumpit,unsigned int flags),有的消息类型只有动作函数doit,有的消息类型只有dump函数dompit,有的消息类型两者皆有。有的消息类型例如RTM_NEWTFILTER,添加一个流量过滤器,则是在tc_filter_init()函数中初始化,该函数实现如下:
当用户层通过NETLINK_ROUTE套接字发送RTM_NEWTFILTER消息用于创建一个流量过滤器时,内核将调用rtnetlink_rcv_msg()函数来处理rtnetlink消息,该函数关键实现如下:
从消息中获取family和type,然后调用rtnl_get_link()函数根据family和type获取link,行5246,调用link->doit回调函数,这里的doit回调函数即为tc_new_tfilter()函数。该函数会进一步解析rtnetlink消息数据包,判断并创建哪种类型的过滤器,具体实现如下:
获取指定的过滤器名字,然后会获取指定协议的过滤器tp。如下代码所示:

如果没有,便根据name创建一个新的tp。如下代码所示:

判断tca[TCA_KIND]不为空和nlmsg_flags为NLM_F_CREATE,然后调用tcf_proto_create()函数创建,该函数实现如下:
行258,分配一个tp;行262,调用tcf_proto_lookup_ops()函数根据kind获取对应的ops。这里以route为例,将获取到cls_route4_ops,如下代码所示:
然后初始化tp,行274,调用route4_init()函数初始化一个route4_head,用于存放过滤器对应的哈希值,该函数实现如下:
tcf_proto创建完成后,将其插入chain中。如下代码所示:
接下来调用对应的get函数,根据tcm_handle获取过滤器。
这里将调用route4_get()函数获取,该函数实现如下:
根据handle从route4_head链表中获取对应的route4_filter。如果为空,便调用change函数进行创建。如下代码所示:
这里将调用ruote4_change()函数进行创建,该函数具体分析见下文。创建成功后,添加一个新的route4过滤器的整个流程便完成了。


三、漏洞原理


漏洞代码出现在route4_change()函数中,该函数实现如下:
行483,首先进一步解析消息数据包;行488,拿出传入的route4_filter,然后判断是否已创建,如果创建过,再判断handle是否一致。由于第一次创建,这里fold为空。接下来进行创建并初始化,如下代码所示:
行493,调用kzalloc()函数分配route4_filter,该结构体大小为144字节。行497,调用tcf_exts_init()函数进行初始化,该函数实现如下:
如果内核开启了CONFIG_NET_CLS_ACT,便调用kcalloc()函数分配exts->actions,分配大小为256字节。初始化完成返回到route4_change()函数中,行501,如果fold不为空,便将fold的数据域赋值给f。行512,然后调用route4_set_parms()函数设置其他参数。行517到行527,将新创建的route4_filter对应的哈希值放到route4_head中。如下代码所示:
行529到行543,该段代码是将旧过滤器的哈希值从route4_head中移除。如下代码所示:
由于是第一次创建,fold为空,因此不进入。但是行529代码是有问题的,这里不仅判断fold是否为空,同时还判断fold->handle是否为空。那如果第一次创建一个handle为0的过滤器,第二次创建新过滤器时,fold不为空,但是fold->handle为0,因此并不会将handle为0的旧过滤器的哈希值从route4_head中移除,保留了对其的索引。接下来开始释放旧过滤器内存,如下代码所示:
第一次创建过滤器时,fold为空,不进入。当第二次创建新过滤器时,fold不为空,行550,调用tcf_queue_work()函数对handle为0的旧过滤器进行释放操作,回调函数为route4_delete_filter_work()函数,该函数实现如下:
行266,最后调用__route4_delete_filter()函数分别释放f->exts和f。当内核调用route4_delete()函数进行释放所有过滤器时,行344,会调用route4_delete_filter_work()函数进行释放,该函数实现如下:
由于handle为0的旧过滤器对应的哈希值依然在route4_head中,因此会对两个对象进行二次释放,分别是route4_filer及对应的exts。该漏洞修复补丁如下代码所示:
将判断条件改成fold是否为空,fold不为空便将其从哈希表中删除。


四、利用研究


4.1 DirtyCred
研究人员提出了一种新的漏洞利用方法,命名为DirtyCred,该利用方法将非特权cred与特权cred进行交换以提升权限,且不需要覆盖内核堆栈上的任何关键数据字段,而是滥用堆内存重写机制来获得特权。该利用技术无需泄露内核地址绕过KASLR,且通用性较强,可跨不同的内核和架构,能绕过广泛采用的内核保护和漏洞利用缓解措施。DirtyCred分为三个步骤,过程如下图所示:
首先,DirtyCred打开一个可写文件“/tmp/x”,它将在内核中分配一个可写file对象。通过触发漏洞,源指针会引用相应缓存中的file对象。然后,DirtyCred尝试将内容写入打开的文件“/tmp/x”中。在实际写入内容之前,内核会检查当前文件是否有写权限,该位置是否可写等。通过检查后,DirtyCred会继续这个实际的文件写入操作,进入第二步。在此步骤中,DirtyCred触发fs_context对象的释放点以解除分配file对象,这就使file对象成为一个被释放的内存点。第三步,DirtyCred打开了一个只读文件“/etc/passwd”,这触发了内核为“/etc/passwd”分配file对象。如上图所示,新分配的file对象接管了被释放的位置。完成此设置后,DirtyCred将释放其暂停的写入操作,而内核将执行实际的内容写入。由于file对象已经被调换,搁置的内容将被重定向到只读文件“/etc/passwd”中。假设写入“/etc/passwd”的内容是“hacker:x:0:0:root:/:/bin/sh”,轻易地注入一个特权账户,从而实现权限提升。
4.2 利用分析

(1)file slab碎片整理

首先创建10000个“/etc/passwd”的file对象,进行file slab碎片整理,为堆喷做准备。

(2)缓存跨越(cross-cache)

当为特定类型的对象创建专用的内存缓存时,该缓存中将只存在该类型的对象,从而防止不同类型的对象相邻。但是,不同slab cache的slab page可以相邻。当slab A与slab B相邻时,slab A末尾的对象与slab B开头的另一个对象相邻。因此,攻击者有可能放置带有任何类型受害者对象的slab页在易受攻击对象的slab page之后,溢出受害者对象来执行攻击。
当一个slab page被释放给伙伴系统时,它会在稍后的某个时候被重用,因为内存页面应该被内核回收。cross-cache攻击的技术是释放slab page中的所有内存槽,强制释放slab page。然后再喷射另一种类型的对象分配新的slab page,回收释放的slab page。如果攻击成功,被释放对象的内存将被另一种类型的对象占用。
由于file对象在专属缓存中分配,而漏洞中route4_filter和exts在通用缓存中分配,正常情况下,两个缓存是隔离的,无法进行常规的对象占坑。作者采用了缓存跨越攻击解决了这个问题。前文讲到route4_filter对象大小为144,在kmalloc-192中分配,exts对象大小为256,在kmalloc-256中分配。file对象大小为256(默认配置情况下),在专属内存中分配。先通过创建basic过滤器在kmalloc-256 slab中进行内存布局。
然后创建route4过滤器,将会创建一个route4_filter漏洞对象和exts对象。最后再进行一部分basic过滤器创建,完成内存布局。关键对象内存分布如下图所示:
然后第一次触发漏洞,释放route4_filter对象和exts对象。然后再全部释放basic->exts对象,让伙伴系统回收kmalloc-256 slab page。
由于内核默认开启slab double free缓解机制,所以这里要乱序释放多个basic->exts。

(3)堆喷占坑

大量打开一个普通文件data2,进行file对象分配占坑route4->exts。缓存跨越攻击成功后,然后再次触发漏洞,第二次释放route4_filter,跟着释放route4->exts,将会把file对象非法释放掉。
关键对象内存布局如下图所示:

(4)寻找file对象空洞

二次释放后,出现了一个file对象空洞,需要找到它。所以此时再次大量打开另一个普通文件uaf,进行file对象堆喷,将会占据这个file对象空洞。然后通过kcmp()系统调用检查 pid1 和 pid2 标识的两个进程是否共享文件描述符定位fds[j]。

(5)延长时间窗口和写恶意数据

找到目标file对象的文件描述符fds[j]后,启动两个线程,slow_write线程向uaf文件中写2G数据,用于延长时间窗口。
然后write_cmd线程通过fds[j]文件描述符写恶意数据。

(6)再次释放并堆喷

最后进行close操作,释放file对象,随即大量打开“/etc/passwd”文件进行file对象堆喷。堆喷成功后,顺利向“/etc/passwsd”写数据,注入一个特权账户完成权限提升。



五、漏洞复现


在内核版本5.4.124中,开启CONFIG_NET_CLS_ACT和CONFIG_NET_SCH_SFQ,可成功复现漏洞。打印调试关键数据,如下图所示:



参考链接:

[1] https://grsecurity.net/how_autoslab_changes_the_memory_unsafety_game
[2] https://www.openwall.com/lists/oss-security/2022/08/09/6
[3] https://www.man7.org/linux/man-pages/man7/rtnetlink.7.html
[4] https://legacy.netdevconf.info/0.1/papers/Rtnetlink-dump-filtering-in-the-kernel.pdf
[5] https://github.com/Markakd/DirtyCred
[6] https://github.com/Markakd/CVE-2022-2588
[7]https://zplin.me/papers/DirtyCred.pdf






启明星辰积极防御实验室(ADLab)





ADLab成立于1999年,是中国安全行业最早成立的攻防技术研究实验室之一,微软MAPP计划核心成员,“黑雀攻击”概念首推者。截止目前,ADLab已通过CVE累计发布安全漏洞近1100个,通过 CNVD/CNNVD累计发布安全漏洞2000余个,持续保持国际网络安全领域一流水准。实验室研究方向涵盖操作系统与应用系统安全研究、移动智能终端安全研究、物联网智能设备安全研究、Web安全研究、工控系统安全研究、云安全研究。研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。






相关阅读

  • 用 ChatGPT 将 Excel 工作效率提高 10 倍!

  • 公众号关注 “GitHubDaily”设为 “星标”,每天带你逛 GitHub!转自:机器之心大家好,我是小 G。在未来,精通 Excel 或许不再是简历亮点了。ChatGPT 自去年 11 月 30 日 OpenAI 重
  • 用 ChatGPT 生成 Excel 公式,太方便了!

  • ↓推荐关注↓来源:机器之心原文链接:https://artificialcorner.com/10x-your-productivity-in-excel-with-chatgpt-6f9536e46d7eChatGPT 自去年 11 月 30 日 OpenAI 重磅推出
  • Python 新一代 HTTP 请求库:httpx

  • 楔子来源:古明地觉的编程教室本次我们来聊一聊 httpx,它是一个 HTTP 请求库。不过说到发送 HTTP 请求,我们首先想到的应该是 requests,但 requests 是一个同步库,目前只能同步发
  • 7 个流行的强化学习算法及代码实现!

  • ↓推荐关注↓作者:Siddhartha Pramanik 来源:Deephub Imba目前流行的强化学习算法包括 Q-learning、SARSA、DDPG、A2C、PPO、DQN 和 TRPO。这些算法已被用于在游戏、机器人和
  • JAVA安全|Gadget篇:Ysoserial CB1链

  • 0x00 前言 JAVA安全系列文章主要为了回顾之前学过的java知识,构建自己的java知识体系,并实际地将java用起来,达到熟练掌握java编程,并能用java编写工具的目的。此系列文章需
  • JAVA安全|Gadget篇:JDK原生链—JDK7u21

  • 本文为JAVA安全系列文章第二十一篇。在没有合适的第三方库存在时,我们仍然有两条原生链可以利用—JDK7u21和JDK8u20。本文学习JDK7u21这条原生链。0x01 JDK7u21链的核心原理
  • JAVA安全|字节码篇:字节码操作库—javassist

  • 0x00 前言 原本打算把这部分内容放到基础篇章的,但随着我的学习,发现这一部分内容其实并不基础,于是又单独开了字节码篇章。这一篇章的主要内容为Javassist、ASM这两个字节
  • Spring环境下有关内存马的回显总结

  • 0x01 前言在学习各种内存马的过程中,关注到了观星实验室的一篇文章,较为全面的列举了在Spring环境下的有关内存马的实现技巧这里我们深入进行学习学习一下0x02 正文前景回顾网

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • ThinkPHP多语言文件包含漏洞分析

  • 更多安全资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn)一、漏洞概述 ThinkPHP是一个开源轻量级PHP框架,其6.0.13及以前版本存在一个文件包
  • ADLab 2022年安全研究回顾

  • 2022年,启明星辰ADLab研究方向重点包括攻防技术安全研究、黑客攻击与威胁研究、主流操作系统及应用安全研究、Web安全研究、云安全研究、智能终端安全研究、工控物联网安全研
  • Android App半自动化静态漏洞挖掘技术分析

  • 更多安全资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn)目 录一、前言二、Android App漏洞扫描的难点三、个人扫描器和商业化漏洞扫描器的