CVE-2023-0179提权利用

前言

在CVE-2023-0179-Nftables整型溢出中,分析了漏洞的成因,接下来分析漏洞的利用。

漏洞利用

根据漏洞成因可以知道,payload_eval_copy_vlan函数存在整型溢出,导致我们将vlan头部结构拷贝到寄存器(NFT_REG32_00-NFT_REG32_15),而该变量时存在与栈上的,因此可以覆盖栈上的其余变量的。

image-20231120215905836

可以发现regs变量是无法覆盖到返回地址。

image-20231120222728305

因此我们需要观察源码,jumpstack变量是在regs变量下方

image-20231120223552586

我们可以通过溢出regs变量覆盖到jumpstack变量。

image-20231120224114239

那么接下来需要观察一下nft_jumpstack结构体中存在哪些变量

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

struct nft_jumpstack {
	const struct nft_chain *chain;
	const struct nft_rule_dp *rule;
	const struct nft_rule_dp *last_rule;
};
  • chain:用于指定在哪个流程进行hook
  • rule:以什么样的规则处理数据包
  • last_rule:规则可能不止一条,因此last_rule用于指向最后一条规则

nft_jumpstack结构体在nft_do_chain函数的作用如下,当状态寄存器被设置为JUMP条件时,意味着需要跳转到其他chain进行处理,因此需要先保存当前chain的状态,这里与函数调用时保存栈时的处理一样,估计因此才命名为jumpstack。并且使用一个全局变量stackptr用于确定保存的chain的先后顺序。在保存完之后,就跳转到目的chain,目的chain则是存储在regs.verdict.chain中。

	...
	switch (regs.verdict.code) {
	case NFT_JUMP:
		if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE))
			return NF_DROP;
		jumpstack[stackptr].chain = chain;
		jumpstack[stackptr].rule = nft_rule_next(rule);
		jumpstack[stackptr].last_rule = last_rule;
		stackptr++;
 	case NFT_GOTO:
		chain = regs.verdict.chain;
		goto do_chain;
	...

还原chain的过程如下,通过递减stackptr来取出存储在jumpstack变量中存储的chainrulelastrule,然后就会跳转到next_rule对还原的rule,进行rule的解析,这里需要注意的是在遍历rule的时候,循环是通过rule < last_rule进行遍历的,因此我们在后续伪造last_rule的时候需要大于rule,否则是无法进入循环内部的。

    next_rule:
        regs.verdict.code = NFT_CONTINUE;
        for (; rule < last_rule; rule = nft_rule_next(rule)) {
            nft_rule_dp_for_each_expr(expr, last, rule) {
                if (expr->ops == &nft_cmp_fast_ops)
                    nft_cmp_fast_eval(expr, &regs);
                else if (expr->ops == &nft_cmp16_fast_ops)
                    nft_cmp16_fast_eval(expr, &regs);
                else if (expr->ops == &nft_bitwise_fast_ops)
                    nft_bitwise_fast_eval(expr, &regs);
                else if (expr->ops != &nft_payload_fast_ops ||
                     !nft_payload_fast_eval(expr, &regs, pkt))
                    expr_call_ops_eval(expr, &regs, pkt);

                if (regs.verdict.code != NFT_CONTINUE)
                    break;
            }
    ...
    if (stackptr > 0) {
            stackptr--;
            chain = jumpstack[stackptr].chain;
            rule = jumpstack[stackptr].rule;
            last_rule = jumpstack[stackptr].last_rule;
            goto next_rule;
        }
    ...

紧接着来看一下nft_rule_dp结构体,可以发现第一个八个字节是一些标志位组成的,而后续的八个字节则是用于存储nft_expr结构体的指针。

struct nft_rule_dp {
	u64				is_last:1,
					dlen:12,
					handle:42;	/* for tracing */
	unsigned char			data[]
		__attribute__((aligned(__alignof__(struct nft_expr))));
};

然后可以看到nft_expr结构体里存储了函数指针,如果我们能够篡改该函数指针就可以劫持程序流程。

struct nft_expr {
	const struct nft_expr_ops	*ops;
	unsigned char			data[]
		__attribute__((aligned(__alignof__(u64))));
};

然后在这篇文章https://www.ctfiot.com/100156.html学习到了一个小技巧。使用ptype /o struct xxx就可以看到具体的结构体信息与偏移。

image-20231121105211637

因此构造的流程如下,首先我们通过漏洞溢出到nft_jumpstack结构体,并且修改rule变量为可控内容的地址同时需要将lastrule的值篡改为比rule更大的值,原因上述已经说过。紧接着在可控内容中伪造一个nft_rule_dp结构体,第一个八字节是填充位,而第二个八字节是需要伪造的函数表指针,同样的我们也将该指针篡改为可控内容的地址,然后再该地址处伪造nft_expr,并且将ops变量指向我们想要执行的函数即可。

image-20231121110958178

通过上述分析已经知道了该如何通过漏洞完成程序流程的劫持,接下来需要分析如果伪造上述几个结构体。

首先在nft_payload_copy_vlan函数中,漏洞点是将vlan头的数据拷贝到指定的寄存器里面,而vlan头的地址是低于寄存器的地址,这就会导致在拷贝完vlan头后会将寄存器中的值也进行拷贝的操作,而寄存器的值我们是能人为控制的,因此就可以完成伪造的操作。

image-20231121112915289

可以看到我们对NFT_REG32_00的赋值会覆盖到jumpstack[7].rule的值,完成了对jumpstack结构体的篡改,这里我们可以通过NFT_REG32_00 - NFT_REG32_15进行赋值,紧接着查看jumpstack哪个值是被赋值。就可以知道哪个jumpstack可以被篡改。

image-20231121113839312

由于我们可以控制regs变量的值,我们可以首先泄露regs的地址,然后在regs上伪造rule即可。然后expr重新指向为jumpstack即可,这里采用了一个小技巧就是将last_rule设置为一个函数地址,由于函数地址的值是大于regs变量的地址值的,因此我们可以节约八个字节。

image-20231121115000312

但是这里有个问题就是我们只能控制八个字节的函数指针,因此是无法构造一个完整的ROP链的,而内核并不存在像用户态下有one_gadget可以只利用八个字节就能完成利用,因此在这里必须使用栈迁移,迁移的目的是一段可以控制的内存,那么这里选用的目的自然就是regs了。那么该如何找栈迁移的gadget呢?,这里我首先采用的使用利用vmlinux-to-elfbzImage的符号表提取出来,然后寻找对应的gadgetgadget类型如下

  • mov rsp,xxx
  • push xxx;pop rsp
  • add rsp,xxx
  • xchg rsp,xxx

上述指令都可以修改rsp寄存器,完成栈迁移的效果。

首先通过vmlinux-to-elf ./bzImage ./vmlinux去提取出符号表

image-20231121115815899

然后通过ropper进行gadget的提取,ropper --file ./vmlinux --nocolor > g

最后这在搜索gadgetcat g | grep 'add rsp.*ret',但是通过尝试发现下述的地址都没办法使用,因为下述地址都不具备可执行的权限。

image-20231121120045631

然后尝试了搜索上述所有的gadget,我都没有找到可以用的gadget,唯一比较接近的gadgetpop rsi的,但是无法控制rsi的寄存器,其实这里一开始我使用的镜像是自己编译的,这里搜索的gadget是需要控制rdi寄存器的,经过多次尝试无果后才使用了作者的config文件重新编译发现还是不可行。

image-20231121120243094

其实我们在编译内核文件时是存在vmlinux文件的,但是那个文件十分的大,使用ropper工具无法分析,就在我准备放弃的时候,想到使用objdump工具进行gadget的提取

使用objdump -d -M intel vmlinux > ./gadget.txt

  • -ddump代码
  • -M是指定汇编代码的格式

objdump提取的速度非常快,提取代码如下,但是它没有ropper搜索gadget那么方便,但是会全的多

image-20231121120811426

这里我首先尝试了搜索栈迁移的gadgetcat gadget.txt | grep -E 'add rsp.*'

image-20231121135057224

可以发现有非常多的匹配的gadget,接着我们在gdb中验证可以使用的gadget,通常在栈进行还原的时候会用到add rsp,xxx,因此都是有效的gadget,然后就是计算栈顶与resg函数地址的差值找到相应的栈迁移gadget即可。

image-20231121135250852

接下就是考虑如何进行提权的利用了,虽然我们可以控制regs但是可控的范围也只有0x40是不足于采用commit_creds(prepare_kernel_cred(0))设置root凭证然后返回到用户空间执行后门的。那么相当的一个办法就是通过覆盖modprobe_path进行提权。这里我找了下列gadget进行modprobe_path的覆盖,将rdi设置为modprobe_pathrax设置为覆盖后的路径即可。

		0xffffffff810d1e6b: mov qword ptr [rdi], rax; ret; 
		0xffffffff81004165: pop rdi; pop rbp; ret

最后就是覆盖完modprobe_path该如何返回到用户态,因为modprobe_path的提权需要在用户态下执行非法文件头的文件,这里作者采用的是将栈还原,通过在rbp中的地址值覆盖会rsp中即可,采用下述gadget

		0xffffffff810b47f0: mov rsp, rbp; pop rbp; ret;

image-20231121141008656

但是在我的环境下直接返回不行,这是因为在返回到 nf_hook_slow函数时,有对状态码的一个检验,而在上述覆盖modprobe_path时,我们设置了rax值,就导致无法将状态码设置成合法值。那分支就会跳转到default,导致报错。在尝试搜索了gadget之后,可以将rax设置为0,但是这回进入到NF_DROP分支 中,但是此时skb变量也被我们破坏了,无法正常执行。

int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
		 const struct nf_hook_entries *e, unsigned int s)
{
	unsigned int verdict;
	int ret;

	for (; s < e->num_hook_entries; s++) {
		verdict = nf_hook_entry_hookfn(&e->hooks[s], skb, state);
		switch (verdict & NF_VERDICT_MASK) {
		case NF_ACCEPT:
			break;
		case NF_DROP:
			kfree_skb_reason(skb,
					 SKB_DROP_REASON_NETFILTER_DROP);
			ret = NF_DROP_GETERR(verdict);
			if (ret == 0)
				ret = -EPERM;
			return ret;
		case NF_QUEUE:
			ret = nf_queue(skb, state, s, verdict);
			if (ret == 1)
				continue;
			return ret;
		default:
			/* Implicit handling for NF_STOLEN, as well as any other
			 * non conventional verdicts.
			 */
			return 0;
		}
	}

	return 1;
}

在尝试很久之后,最终放弃正常返回的这个选项,然后我在rbp中搜索是否有合适的返回地址。最后在rbp中我找到了一个do_softirq函数

image-20231121142144155

该函数是一个软中断处理的函数,当时我就猜想,如果这个函数返回了,应该不会影响程序的执行。

image-20231121142513768

尝试运行之后,发现还是有内核异常,顿时有点失望。

image-20231121142943996

但是在操控命令行的时候是能够正常输入命令的,说明我们成功返回到用户态了。

image-20231121143107629

最后就是查看是否将新用户写入到/etc/passwd中了,最终完成写入。完结撒花!。

image-20231121143252463

完整exp可以参考https://github.com/h0pe-ay/Vulnerability-Reproduction/blob/master/CVE-2023-0179(nftables)/poc.c

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】通过profiles设置环境

效果图&#xff0c;通过profiles设置环境 在父级pom.xml中添加配置 <profiles><profile><id>dev</id><properties><application.environment>dev</application.environment></properties><activation><activeByDefau…

OceanBase:OBServer节点管理

目录 1.查看节点 2.添加节点 2.1 创建数据目录 2.2.OceanBase 运行时所依赖的部分三方动态库 2.3.安装 OceanBase 数据库的 RPM 包 2.4.启动节点 observer 进程 2.5.向集群中添加节点 3.隔离节点 4.重启节点 4.1 停止服务 4.2 转储 4.3 关闭进程 4.4 启动进程 4.…

【原创】为MybatisPlus增加一个逻辑删除插件,让XML中的SQL也能自动增加逻辑删除功能

前言 看到这个标题有人就要说了&#xff0c;D哥啊&#xff0c;MybatisPlus不是本来就有逻辑删除的配置吗&#xff0c;比如TableLogic注解&#xff0c;配置文件里也能添加如下配置设置逻辑删除。 mybatis-plus:mapper-locations: classpath*:mapper/*.xmlconfiguration:mapUnd…

Java-认识String类

本章重点&#xff1a; 1. 认识 String 类 2. 了解 String 类的基本用法 3. 熟练掌握 String 类的常见操作 4. 认识字符串常量池 5. 认识 StringBuffer 和 StringBuilder 1.String类的重要性 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组…

C++中的内存管理

✨前言✨ &#x1f4d8; 博客主页&#xff1a;to Keep博客主页 &#x1f646;欢迎关注&#xff0c;&#x1f44d;点赞&#xff0c;&#x1f4dd;留言评论 ⏳首发时间&#xff1a;2023年11月21日 &#x1f4e8; 博主码云地址&#xff1a;博主码云地址 &#x1f4d5;参考书籍&…

如何选择适合的开源框架来构建微服务架构?

随着科技的飞速发展&#xff0c;云计算和大规模应用的需求日益显著&#xff0c;这促使微服务架构在软件开发领域中占据了主流地位。微服务架构的广泛应用为开发人员提供了灵活性、可伸缩性和高可用性&#xff0c;从而推动了快速的应用程序开发。然而&#xff0c;在构建微服务架…

ky10 server x86 安装、更新openssl3.1.4(在线编译安装、离线安装)

查看openssl版本 openssl version 离线编译安装升级 #!/bin/shOPENSSLVER3.1.4OPENSSL_Vopenssl versionecho "当前OpenSSL 版本 ${OPENSSL_V}" #------------------------------------------------ #wget https://www.openssl.org/source/openssl-3.1.4.tar.gzech…

git撤销某一次commit提交

一&#xff1a;撤销上一次commit提交&#xff0c;但不删除修改的代码 可以使用使用VSCode 二&#xff1a;使用 git reset --hard命令删除提交时&#xff0c;将会删除该提交及其之后的所有更改&#xff08;相当于你想要回滚到的提交的提交ID&#xff09; git reset --hard 版本…

ubuntu18.04安装并运行ORB-SLAM2

查看版本号 lsb_release -a 换源 Ubuntu系统自带的源都是国外的网址&#xff0c;国内用户在使用的时候下载比较慢甚至无法获取&#xff0c;需要替换成国内的镜像源 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list.old 打开文件 sudo gedit /etc/apt/so…

【Python】153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1*1*1+5*5*5+3*3*3。编程求所有满足这种条件的三位十进制数。

问题描述 153是一个非常特殊的数&#xff0c;它等于它的每位数字的立方和&#xff0c;即1531*1*15*5*53*3*3。编程求所有满足这种条件的三位十进制数。 输出格式 按从小到大的顺序输出满足条件的三位十进制数&#xff0c;每个数占一行。 方法一&#xff1a; for i in range(10…

入行IC | 从小白助理级,到总监专家级,到底要经历怎样的成长阶段呢?

《中国集成电路产业人才发展报告》是业内和IC设计、IC人才都息息相关的一份报告。 &#xff08;文末可领全部报告资料&#xff09; * 从报告数据来看&#xff0c;无论在半导体产业的哪个环节&#xff0c;个人发展路径和年薪待遇都是逐级攀升的趋势。 那么从小白助理级&a…

k8s-pod管理 3

pod是可以创建和管理k8s 计算的最小可部署单元&#xff0c;一个pod 代表着集群中运行的一个进程&#xff0c;每个pod 都有一个唯一的ip pod包裹了容器 下载测试镜像 创建自主式的pod 查看创建的pod的详情信息 删除pod 创建控制器 副本过多&#xff0c;需要进行负载均衡减轻节点…

外部 prometheus监控k8s集群资源

prometheus监控k8s集群资源 一&#xff0c;通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二&#xff0c;通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…

【操作系统】文件系统的实现

文章目录 文件系统的层次结构文件系统的实现目录实现线性列表哈希表 文件的实现连续分配链接分配索引分配 文件存储空间管理空闲表法与空闲链表法成组链接法位示图法 文件系统的层次结构 文件系统从上往下分为了五层&#xff0c;分别是用户调用接口、文件目录系统、存取控制模…

解放双手!一键助你快速发圈、批量加好友,好用哭了!

朋友们&#xff0c;你们有没有经历过管理多个微信账号的繁琐和压力&#xff1f; 会不会因为忙不过来&#xff0c;忘记及时回复客户&#xff0c;错过了推广的时机&#xff1f; 别担心&#xff0c;现在有了微信管理系统&#xff0c;一切都变得简单轻松起来&#xff01; 微信管…

打造高效医患沟通:陪诊小程序开发技术指南

随着科技的不断发展&#xff0c;陪诊小程序作为医患沟通的新工具逐渐成为关注焦点。本文将带领你通过使用React和Node.js技术栈&#xff0c;构建一个功能强大且用户友好的陪诊小程序&#xff0c;实现医患互动的便捷和高效。 1. 准备工作 确保你的开发环境中已安装了Node.js和…

Unity下载资源且保存

UnityWebRequest(WWW——已过时) 替代&#xff1a;Unity不再支持WWW后&#xff0c;使用UnityWebRequest完成web请求。 Unity - Scripting API: UnityWebRequest (unity3d.com)https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.html if (www.isNetworkEr…

Java 多线程之 volatile(可见性/重排序)

文章目录 一、概述二、使用方法三、测试程序3.1 验证可见性的示例3.2 验证指令重排序的示例 一、概述 在Java中&#xff0c;volatile 关键字用于修饰变量&#xff0c;其作用是确保多个线程之间对该变量的可见性和禁止指令重排序优化。 当一个变量被声明为volatile时&#xff0…

基于Vue+SpringBoot的校园电商物流云平台开源项目

项目编号&#xff1a; S 034 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S034&#xff0c;文末获取源码。} 项目编号&#xff1a;S034&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 商品数据模块2.3 快…

企业怎么进行人事管理?一篇文章带你了解!

阅读本文你将了解企业如何运用数字化工具进行人事管理&#xff1a;一、数字化、线上化&#xff0c;解放人力&#xff1b;二、规范管理流程&#xff0c;提升处理效率&#xff1b;三、数据分析可视化&#xff0c;支持并优化决策&#xff1b;四、个性化定制&#xff0c;灵活适应需…
最新文章