Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >QEMU 虚拟机逃逸漏洞(CVE-2019-14378)漏洞分析

QEMU 虚拟机逃逸漏洞(CVE-2019-14378)漏洞分析

作者头像
用户1423082
发布于 2024-12-31 12:08:17
发布于 2024-12-31 12:08:17
9600
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

这是qemu在网络实现的时候的一个指针错误,当重组大量的ipv4分段数据包时会触发错误,这还是大牛通过代码审计发现的,厉害啊。

漏洞细节

qemu的网络有两部分 1、为虚拟机提供的虚拟网卡(比如PCI网卡) 2、与网络接口控制器交互的网络后端(就是将网络数据包给到主机网络)

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

而本漏洞是在SLiRP中的数据包重组中出现的错误。

数据包重组那就需要了解ip分片,ip层的结构如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

分片在Flags那里,主要是低3个bit

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Bit 0: 保留为, 必须为0
Bit 1: (DF) 0 = 分片, 1 = 不分片.
Bit 2: (MF) 0 =最后一个ip包, 1 = 后面还有分片
Fragment Offset: 13 bits

下面看下相关的结构体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct mbuf {
    /* header at beginning of each mbuf: */
    struct mbuf *m_next; /* Linked list of mbufs */
    struct mbuf *m_prev;
    struct mbuf *m_nextpkt; /* Next packet in queue/record */
    struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */
    int m_flags; /* Misc flags */

    int m_size; /* Size of mbuf, from m_dat or m_ext */
    struct socket *m_so;

    char *m_data; /* Current location of data */
    int m_len; /* Amount of data in this mbuf, from m_data */

    ...

    char *m_ext;
    /* start of dynamic buffer area, must be last element */
    char m_dat[];
};

mbuf是储存接收到的ip层的信息。有两个buffer,一个是m_dat ,另一个是m_ext,他是m_dat不足以储存的时候,通过在堆上分配内存解决不足的问题

在nat转换的时候,如果传入的数据包是分片的,则应在编辑和重新传输之前重新组装它们。 这个重组由ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)函数完成。 ip包含当前的IP数据包数据,fp是包含分段数据包的链表。

ip_reass执行以下操作: 1、如果第一个分配的fp为NULL,创建重组队列并将ip插入此队列。 2、检查片段是否与先前收到的片段重复,然后丢弃它。 3、如果收到所有分段的数据包,则重新组装它。 通过修改第一个数据包的头部为新的ip header。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * Take incoming datagram fragment and try to
 * reassemble it into whole datagram.  If a chain for
 * reassembly of this datagram already exists, then it
 * is given as fp; otherwise have to make a chain.
 */
static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
{

    ...
    ...

    /*
     * Reassembly is complete; concatenate fragments.
     */
    q = fp->frag_link.next;
    m = dtom(slirp, q);

    q = (struct ipasfrag *)q->ipf_next;
    while (q != (struct ipasfrag *)&fp->frag_link) {
        struct mbuf *t = dtom(slirp, q);
        q = (struct ipasfrag *)q->ipf_next;
        m_cat(m, t);
    }

    /*
     * Create header for new ip packet by
     * modifying header of first packet;
     * dequeue and discard fragment reassembly header.
     * Make header visible.
     */
    q = fp->frag_link.next;

    /*
     * If the fragments concatenated to an mbuf that's
     * bigger than the total size of the fragment, then and
     * m_ext buffer was alloced. But fp->ipq_next points to
     * the old buffer (in the mbuf), so we must point ip
     * into the new buffer.
     */
    if (m->m_flags & M_EXT) {
        int delta = (char *)q - m->m_dat;
        q = (struct ipasfrag *)(m->m_ext + delta);
    }

这个漏洞在于计算变量delta的值有问题,而上面这个代码假定了第一个分片数据包不会在external buffer中分配(m_ext)。 当分片数据在mbuf-> m_dat(q将在m_dat内)时,计算q-m-> dat有效(q是包含分片链表和数据包数据的结构)。

否则,如果分配了m_ext缓冲区,则q将位于external buffer ,那么delta的计算就是错误的。

q的数据结构是ipasfrag:就是有一个前向指针跟后向指针,以及包含了一个ip头

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * Ip header, when holding a fragment.
 *
 * Note: ipf_link must be at same offset as frag_link above
 */
struct ipasfrag {
    struct qlink ipf_link;
    struct ip ipf_ip;
};

struct qlink {
    void *next, *prev;
};

我们可以调试看看q的某个时刻的状态是怎样的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ p *q
$30 = {
  ipf_link = {
    next = 0x7f9e08084ed0,
    prev = 0x7f9e0808487c
  },
  ipf_ip = {
    ip_hl = 0x5,
    ip_v = 0x4,
    ip_tos = 0x0,
    ip_len = 0x8,
    ip_id = 0x7f3a,
    ip_off = 0x8,
    ip_ttl = 0x40,
    ip_p = 0x1,
    ip_sum = 0x95e3,
    ip_src = {
      s_addr = 0xf02000a
    },
    ip_dst = {
      s_addr = 0x202000a
    }
  }
}

可以看到确实是两个ipasfrag前后指针还有ip头信息

我们继续调试运行到下面地方

我们查看下数据结构,可以看到确实此时的q在m_ext的后面,而m_dat在老前面了,那么q - m->m_dat就是负数了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ p q
$41 = (struct ipasfrag *) 0x7f9e0808882c
gdb-peda$ p *m
$42 = {
  m_next = 0x7f9e080881a0,
  m_prev = 0x7f9e080874c0,
  m_nextpkt = 0x0,
  m_prevpkt = 0x0,
  m_flags = 0xd,
  m_size = 0xcde,
  m_so = 0x0,
  m_data = 0x7f9e08088850 "",
  m_len = 0xc98,
  slirp = 0x563aa67a6380,
  resolution_requested = 0x0,
  expiration_date = 0xffffffffffffffff,
  m_ext = 0x7f9e08088810 "",
  m_dat = 0x7f9e08086eb0 ""
}
gdb-peda$ p *q
$43 = {
  ipf_link = {
    next = 0x7f9e0808487c,
    prev = 0x7f9e08087520
  },
  ipf_ip = {
    ip_hl = 0x5,
    ip_v = 0x4,
    ip_tos = 0x1,
    ip_len = 0xc90,
    ip_id = 0x7f3e,
    ip_off = 0x0,
    ip_ttl = 0x40,
    ip_p = 0x1,
    ip_sum = 0x1c43,
    ip_src = {
      s_addr = 0xffffff8b
    },
    ip_dst = {
      s_addr = 0x0
    }
  }
}

简单的示意图如下:(忽略了分配了m_ext缓冲区,则q将位于external buffer)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+------------------------------+
|                              |
|                              |
|                              |
|                              |
| m_dat 0x7f9e08086eb0         |
|                              |
|                              |
+------------------------------+
|                              |
|m->m_ext 0x7f9e08088810       |
|                              |
|                              |
|q 0x7f9e0808882c              |
|                              |
|                              |
|                              |
+------------------------------+

之后,新计算的指针q被转换为ip结构并且修改部分字段。由于错误地计算了delta,ip将指向不正确的位置,并且ip_src和ip_dst可用于将我们可控的数据写入错误计算的ip的位置。 如果计算出的ip位于没有映射的内存区域,这就会使qemu崩溃。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
slirp/src/ip_input.c:ip_reass
    ip = fragtoip(q);   //转换
    ip->ip_len = next;
    ip->ip_tos &= ~1;
    ip->ip_src = fp->ipq_src;
    ip->ip_dst = fp->ipq_dst;

参考

https://blog.bi0s.in/2019/08/24/Pwn/VM-Escape/2019-07-29-qemu-vm-escape-cve-2019-14378/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-10-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
分享两个 CVE 漏洞的分析报告
因为 MS_T120 这个 channel 是内部 Channel,MS_T120 Channel 被绑定两次(内部绑定一次,然后我们又绑定一次——id 不是 31)。由于绑定的时候没有限制,所以绑定在两个不同的 ID 下,因此 MS_T120 Channel 就有两个引用,假如我们关闭 channel,就触发一次 free,而我们断开连接系统默认也会 free,那就变成了 Double Free 了(其实 Double Free 是 UAF 的特殊情况,因为这个 USE 是 free 而已)。
信安之路
2019/10/15
1.8K0
Linux 1.2.13 -- IP分片重组源码分析
本文源码解析参考: 深入理解TCP/IP协议的实现之ip分片重组 – 基于linux1.2.13
大忽悠爱学习
2023/10/11
6630
Linux 1.2.13 -- IP分片重组源码分析
MIT 6.S081 Lab 11 -- NetWork - 下
上一节我们总体介绍了一下手册中有关数据接收和传输的章节,本节借助上节的基础来完成lab的具体代码实现。
大忽悠爱学习
2023/10/11
3300
MIT 6.S081 Lab 11 -- NetWork - 下
6.S081/6.828: xv6源码分析--networking
目的主机收到报文后会自底而上,层层处理,每一层header包含下一步处理的协议类型。
冰寒火
2022/11/20
1.1K0
CTF QEMU 虚拟机逃逸之BlizzardCTF 2017 Strng
内存映射I/O (Memory-mapped I/O —— MMIO) 端口映射I/O (port-mapped I/O —— PMIO)
用户1423082
2024/12/31
1070
CTF QEMU 虚拟机逃逸之BlizzardCTF 2017 Strng
CTF PWN之house of orange
题目链接:https://github.com/giantbranch/CTF_PWN/tree/master/other/houseoforange
用户1423082
2024/12/31
430
CTF PWN之house of orange
VM escape 之 QEMU Case Study
学习的来源是phrack网站的paper,这个应是上年就看到了,现在才去尝试实践与学习。
用户1423082
2024/12/31
590
VM escape 之 QEMU Case Study
CVE-2020-9967-Apple macOS 6LowPAN漏洞
受Kevin Backhouse在寻找XNU远程漏洞方面的伟大工作的启发,我决定花一些时间看看CodeQL,并进行一些变种分析。这导致了在macOS 10.15.4的6LowPAN代码中发现了一个本地根到内核(虽然被苹果记录为远程)的漏洞。
Khan安全团队
2020/12/28
8930
CVE-2020-9967-Apple macOS 6LowPAN漏洞
MIT_6.s081_Lab
输入 file ./kernel/kernel载入符号表,然后target remote loaclhost:26000即可:
用户7267083
2023/03/20
1.3K0
MIT_6.s081_Lab
SeedLab——Packet Sniffing and Spoofing Lab
在这个实验中,攻击者需要能够嗅探数据包,但在容器内运行嗅探程序会有问题,因为容器实际上连接到一个虚拟交换机,所以它只能看到自己的流量,无法看到其他容器之间的数据包。为了解决这个问题,我们在攻击者容器中使用主机模式(host mode)。
Andromeda
2023/11/22
1.1K0
SeedLab——Packet Sniffing and Spoofing Lab
CTF QEMU 虚拟机逃逸之Defcon 2018 - EC3
这个题目给的qemu-system-x86_64的符号是被stripped掉了,相当于增加了点难度
用户1423082
2024/12/31
730
CTF QEMU 虚拟机逃逸之Defcon 2018 - EC3
learning:gre tunnel plugins
GRE(Generic Routing Encapsulation,通用路由封装)协议用来对某种协议(如IP、MPLS、以太网)的数据报文进行封装,使这些被封装的数据报文能够在另一个网络(如IP)中传输。封装前后数据报文的网络层协议可以相同,也可以不同。封装后的数据报文在网络中传输的路径,称为GRE隧道。GRE隧道是一个虚拟的点到点的连接,其两端的设备分别对数据报文进行封装及解封装。
dpdk-vpp源码解读
2024/01/09
4090
learning:gre tunnel plugins
learning:vrrp vmac config
最近在测试vrrp功能的时候发现一个问题,就是主备同时在线的时候,在ping虚拟网关的时候,会出现下面的问题:
dpdk-vpp源码解读
2023/01/04
7720
learning:vrrp vmac config
Linux用户态协议栈与DPDK构建高性能应用
这里使用了已经搭建好的dpdk环境,dpdk的搭建过程网上有很多教程可以参考,后面有空再做一篇dpdk环境搭建文章吧! (1)检查网卡状态
Lion 莱恩呀
2024/09/15
3430
Linux用户态协议栈与DPDK构建高性能应用
利用vpp和内核协议栈通信机制实现虚拟机上网
本文参考博客(https://blog.csdn.net/illina/article/details/81669944)来学习一下利用vpp实现虚拟机上网功能。主要是为了学习虚拟网卡功能在vpn场景中应用比较广泛。
dpdk-vpp源码解读
2023/03/07
2.5K0
利用vpp和内核协议栈通信机制实现虚拟机上网
learning:vpp/classify(2)
作用如下图所示从table内存池上申请table内存,在main_heap上申请桶占用空间,从系统内存映射classify session中匹配规则表配置空间。这里操作和bihash一致。
dpdk-vpp源码解读
2023/01/04
1.9K0
learning:vpp/classify(2)
iOS12-2 越狱漏洞分析
这是一个 UAF 的洞,是通过tfp0的方式来拿到内核代码执行的权限了,一般的利用方式我们都还是比较熟悉了,而且 UAF 的利用方式我们通常都是通过ROP的方式来提权,所以都要配合一个信息泄漏,所以这次的利用方式还是非常值得我们去学习的。通过代码结构来看应该是少不了 bazad 的帮助,通过他那个软件工程式的exploit就凸显了斯坦福博士的风格。不过整体都是 C++ 下的看的着实有点难受。
信安之路
2019/07/30
1.2K0
tcpdump命令使用简介
tcpdump 是一款强大的网络抓包工具,运行在 linux 平台上。熟悉 tcpdump 的使用能够帮助你分析、调试网络数据。
吴易娃
2024/01/12
5200
Learning VPP: OSPF routing protocol
前面文章:learning:vppsb router插件编译 介绍了vppsb router插件在Centos7内核版本3.10上的基于vpp 21.06版本的编译,并将修改后代码放在github上《链接https://github.com/jin13417/vppsb/tree/vpp_21.06》。本文主要参考博文《Learning VPP: OSPF routing protocol》学习使用vppsb的router插件搭建ospf学习环境。
dpdk-vpp源码解读
2023/03/07
2.7K1
Learning VPP: OSPF routing protocol
vpp IPsec with DPDK Cryptodev have buffer resource leak.
此刻是否已经准备下班或者已经在下班的路上,首先提前祝大家五一快乐,北京疫情正处于关键阶段,各位出行注意防护。
dpdk-vpp源码解读
2023/01/04
1.3K0
vpp IPsec with DPDK Cryptodev have  buffer resource leak.
相关推荐
分享两个 CVE 漏洞的分析报告
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验