深入分析QEMU虚拟机逃逸漏洞
字数 1460 2025-08-03 16:49:46

QEMU虚拟机逃逸漏洞CVE-2019-14378深入分析与利用

漏洞概述

CVE-2019-14378是QEMU网络后端中发现的一个指针计算错误漏洞,当重新组装大型IPv4分段数据包时触发。该漏洞存在于SLiRP用户网络后端的数据包重组代码中,可能导致虚拟机逃逸。

技术背景

QEMU网络架构

QEMU内部网络功能分为两部分:

  1. 提供给客户机的虚拟网络设备(如PCI网卡)
  2. 与模拟NIC交互的网络后端(如将数据包推送至宿主机的网络)

默认情况下,QEMU会为guest虚拟机创建SLiRP用户网络后端和适当的虚拟网络设备(如e1000 PCI卡)。

IP分段机制

IP协议在传输数据包时,将数据包分为若干分段进行传输,并在目标系统中重组,称为IP分段(Fragmentation)。分段标志位:

  • Bit 0: 保留未用,必须为零
  • Bit 1: (DF) 0 = 允许分段,1 = 不允许分段
  • Bit 2: (MF) 0 = 最后分段,1 = 更多分段

漏洞分析

关键数据结构

struct mbuf {
    struct mbuf *m_next;        // 链接列表中的下一个mbuf
    struct mbuf *m_prev;
    struct mbuf *m_nextpkt;     // 队列/记录中的下一个数据包
    struct mbuf *m_prevpkt;
    int m_flags;                // 杂项标志
    int m_size;                 // mbuf大小,来自m_dat或m_ext
    struct socket *m_so;
    char *m_data;               // 当前数据位置
    int m_len;                  // 此mbuf中的数据量
    char *m_ext;                // 动态缓冲区起始位置
    char m_dat[];               // 内部缓冲区
};

漏洞位置

漏洞位于ip_reass()函数中,当处理IP分段重组时:

if (m->m_flags & M_EXT) {
    int delta = (char *)q - m->m_dat;  // 错误计算
    q = (struct ipasfrag *)(m->m_ext + delta);
}

问题在于:

  1. 代码假设第一个分段数据包不会被分配到外部缓冲区(m_ext)
  2. 当数据包数据位于mbuf->m_dat中时,q - m->dat计算正确
  3. 如果分配了m_ext缓冲区,q位于外部缓冲区中,delta计算错误

漏洞触发流程

  1. NAT转换时,如果传入数据包是分段的,首先需要重组
  2. 重组由ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)完成
  3. 重组步骤:
    • 第一个分段到达(fp == NULL)时创建重组队列并插入ip
    • 检查是否与先前分段重复
    • 收到所有分段后重组数据包
    • 修改第一个数据包的头部创建新IP数据包头部

漏洞利用

堆布局控制

利用堆喷射技术控制内存分配:

malloc(0x670)  // mbuf对象
if(pkt_len + TCPIPHDR_DELTA + 2 > 0x608)
   malloc(pkt_len + TCPIPHDR_DELTA + 2)  // 外部缓冲区
if(ip->ip_off & IP_MF)
   malloc(0x670)  // 分段队列

任意写操作实现

  1. 发送ID为"0xdead"且MF位为1的数据包
  2. 发送ID为"0xcafe"且MF位为1的数据包
  3. 触发漏洞覆盖0xcafe数据包的m_len,使m_data+m_len指向0xdead数据包的m_data
  4. 发送ID为"0xcafe"且MF位为0的数据包,触发重组并用目标地址覆盖"0xdead"数据包的m_data
  5. 发送ID为"0xdead"且MF位为0的数据包,将其内容写入m_data

数据泄露技术

利用ICMP回应请求服务泄露数据:

  1. 通过任意写操作在堆上创建伪ICMP报头
  2. 发送设置了MF位的ICMP请求
  3. 部分覆盖m_data指向伪造的报头
  4. 发送MF位为0的数据包结束ICMP请求
  5. 接收从宿主机泄漏的重要数据

代码执行实现

利用QEMU定时器机制:

struct QEMUTimer {
    int64_t expire_time;        // 纳秒
    QEMUTimerList *timer_list;
    QEMUTimerCB *cb;            // 回调函数
    void *opaque;               // 参数
    QEMUTimer *next;
    int scale;
};

struct QEMUTimerList {
    QEMUClock *clock;
    QemuMutex active_timers_lock;
    QEMUTimer *active_timers;
    QLIST_ENTRY(QEMUTimerList) list;
    QEMUTimerListNotifyCB *notify_cb;
    void *notify_opaque;
    QemuEvent timers_done_ev;
};

攻击步骤:

  1. 创建伪造的QEMUTimer,设置回调函数为system,参数为命令
  2. 创建伪造的QEMUTImerList包含伪造的QEMUTimer
  3. 使用伪造的QEMUTimerList覆盖main_loop_tlg的元素

防御建议

  1. 修复delta计算逻辑,正确处理m_ext情况
  2. 添加对m_len的边界检查
  3. 启用QEMU的所有安全保护机制(ASLR, PIE等)
  4. 限制虚拟机网络访问权限
  5. 及时更新QEMU到修复版本

参考资源

  1. QEMU Networking
  2. IP Fragmentation
  3. Virtunoid: A KVM Guest-Host privilege escalation
  4. CVE-2019-6778
  5. 完整exploit代码
QEMU虚拟机逃逸漏洞CVE-2019-14378深入分析与利用 漏洞概述 CVE-2019-14378是QEMU网络后端中发现的一个指针计算错误漏洞,当重新组装大型IPv4分段数据包时触发。该漏洞存在于SLiRP用户网络后端的数据包重组代码中,可能导致虚拟机逃逸。 技术背景 QEMU网络架构 QEMU内部网络功能分为两部分: 提供给客户机的虚拟网络设备(如PCI网卡) 与模拟NIC交互的网络后端(如将数据包推送至宿主机的网络) 默认情况下,QEMU会为guest虚拟机创建SLiRP用户网络后端和适当的虚拟网络设备(如e1000 PCI卡)。 IP分段机制 IP协议在传输数据包时,将数据包分为若干分段进行传输,并在目标系统中重组,称为IP分段(Fragmentation)。分段标志位: Bit 0: 保留未用,必须为零 Bit 1: (DF) 0 = 允许分段,1 = 不允许分段 Bit 2: (MF) 0 = 最后分段,1 = 更多分段 漏洞分析 关键数据结构 漏洞位置 漏洞位于 ip_reass() 函数中,当处理IP分段重组时: 问题在于: 代码假设第一个分段数据包不会被分配到外部缓冲区(m_ ext) 当数据包数据位于mbuf->m_ dat中时, q - m->dat 计算正确 如果分配了m_ ext缓冲区,q位于外部缓冲区中,delta计算错误 漏洞触发流程 NAT转换时,如果传入数据包是分段的,首先需要重组 重组由 ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp) 完成 重组步骤: 第一个分段到达(fp == NULL)时创建重组队列并插入ip 检查是否与先前分段重复 收到所有分段后重组数据包 修改第一个数据包的头部创建新IP数据包头部 漏洞利用 堆布局控制 利用堆喷射技术控制内存分配: 任意写操作实现 发送ID为"0xdead"且MF位为1的数据包 发送ID为"0xcafe"且MF位为1的数据包 触发漏洞覆盖0xcafe数据包的m_ len,使m_ data+m_ len指向0xdead数据包的m_ data 发送ID为"0xcafe"且MF位为0的数据包,触发重组并用目标地址覆盖"0xdead"数据包的m_ data 发送ID为"0xdead"且MF位为0的数据包,将其内容写入m_ data 数据泄露技术 利用ICMP回应请求服务泄露数据: 通过任意写操作在堆上创建伪ICMP报头 发送设置了MF位的ICMP请求 部分覆盖m_ data指向伪造的报头 发送MF位为0的数据包结束ICMP请求 接收从宿主机泄漏的重要数据 代码执行实现 利用QEMU定时器机制: 攻击步骤: 创建伪造的QEMUTimer,设置回调函数为system,参数为命令 创建伪造的QEMUTImerList包含伪造的QEMUTimer 使用伪造的QEMUTimerList覆盖main_ loop_ tlg的元素 防御建议 修复delta计算逻辑,正确处理m_ ext情况 添加对m_ len的边界检查 启用QEMU的所有安全保护机制(ASLR, PIE等) 限制虚拟机网络访问权限 及时更新QEMU到修复版本 参考资源 QEMU Networking IP Fragmentation Virtunoid: A KVM Guest-Host privilege escalation CVE-2019-6778 完整exploit代码