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 触发路径

  1. 通过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;
    
  2. 通过Opt_max_credits分支传入错误参数,导致ctx->password被释放但指针未置空

  3. 关闭文件系统对应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_payloadshm_file_data结构体重叠泄露vm_ops获取内核基地址:

struct shm_file_data {
    int id;
    struct ipc_namespace *ns;
    struct file *file;
    const struct vm_operations_struct *vm_ops;
};

步骤

  1. 在kmalloc-32分配ctx->password
  2. 触发漏洞释放ctx->password
  3. 分配user_key_payload占位刚释放的ctx->password
  4. 再次释放ctx->password导致user_key_payload被释放
  5. 大量分配shm_file_data占位刚释放的user_key_payload
  6. 此时user_key_payloadshm_file_data重叠,通过user_key_payload读出shm_file_data内容

4.1.2 堆地址泄露

利用simple_xattruser_key_payload泄露堆地址:

struct simple_xattr {
    struct list_head list;
    char *name;
    size_t size;
    char value[];
};

特点

  • value部分数据由用户态控制
  • 通过文件的多个xattr通过list双向链表管理
  • 泄露list可以找到存放用户数据的堆地址

流程

  1. 使simple_xattr(VX)和user_key_payload在kmalloc-96上重叠
  2. 通过simple_xattr_set给VX对应的文件增加8192大小的xattr
  3. 新xattr会插入到VX的list->prev
  4. 利用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;
}

步骤

  1. 利用Double Free实现ovl_dir_file结构体的UAF
  2. 使用ramfs_parse_param占位ovl_dir_file
  3. 控制od->realfile指向泄露的堆地址
  4. 在伪造的realfile中让f_op指向另一个泄露的堆地址
  5. 触发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 最终利用

  1. 在kmalloc-8192 #1和kmalloc-8192 #2分别伪造file结构体和f_op
  2. 用户态对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. 利用技巧总结

  1. 堆风水:精确控制内核对象在特定slab中的布局
  2. 信息泄露
    • 利用shm_file_data泄露内核基地址
    • 利用simple_xattr链表泄露堆地址
  3. 对象劫持
    • 通过Double Free实现ovl_dir_file的UAF
    • 伪造filefile_operations结构体
  4. 控制流劫持:通过lseek触发ROP链执行

7. 防御建议

  1. 及时更新内核补丁
  2. 启用KASLR和SMAP/SMEP
  3. 限制非特权用户的fsconfig系统调用访问
  4. 使用内存安全语言重写敏感内核模块

8. 参考资料

  1. Linux内核官方补丁
  2. Google安全研究
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 函数: 2.2 根本原因 当解析 max_credits 参数失败时,代码会跳转到 cifs_parse_mount_err 标签释放 ctx->password ,但 没有将指针置空 ,导致双重释放(Double Free)问题。 2.3 触发路径 通过 Opt_pass 分配 ctx->password : 通过 Opt_max_credits 分支传入错误参数,导致 ctx->password 被释放但指针未置空 关闭文件系统对应fd导致 ctx->password 再次被释放 3. 补丁分析 补丁修复了指针未置空的问题: 4. 漏洞利用技术 4.1 信息泄露阶段 4.1.1 内核基地址泄露 利用 user_key_payload 和 shm_file_data 结构体重叠泄露 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 泄露堆地址: 特点 : 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 步骤 : 利用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 命令: 用户态代码: 4.3 最终利用 在kmalloc-8192 #1和kmalloc-8192 #2分别伪造 file 结构体和 f_op 用户态对 ovl_dir_file 的fd调用 lseek 系统调用执行ROP 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 结构体 控制流劫持 :通过 lseek 触发ROP链执行 7. 防御建议 及时更新内核补丁 启用KASLR和SMAP/SMEP 限制非特权用户的 fsconfig 系统调用访问 使用内存安全语言重写敏感内核模块 8. 参考资料 Linux内核官方补丁 Google安全研究