0x01 简述

meltdown——“熔断”漏洞,是一种侧信道攻击,信道是CPU读取内存的时间。利用该漏洞,我们可以在用户态读取内核态任意地址的数据。该漏洞于2018年1月被大众所知,本文主要参考蒸米前辈的文章,并分析该漏洞利用的原理。

PS:这个漏洞我从刚出来(2018年1月)就开始分析了,最近重新整理发现遗漏了很多细节,可见随时整理反思有多重要。

Q1:为什么可以获取内核态的数据?

假设用户态存在如下汇编指令:

; rcx = kernel address
; rbx = array_addr in userspace, assume array[256*4096]
mov al, byte [rcx] ; read kernel address value and must be failed!
shl rax, 0xc  ; rax = al *4096
mov rcx, qword [rbx + rax] ; read array[X*4096] 

先解释一下汇编代码:

  • .line3 尝试从内核态读1byte的数据,假设为X,范围 0-255。
  • .line4 将X*4096,数组所在进程空间对应到内核页表中属于不同的页(假设一页是4K)。
  • .line5 读rbx数组中不同页表中的值,保存到rcx中。

CPU做了哪些事情呢?CPU执行line3时,会知道当前是kernel的addr,权限检查读取失败。但是这一步骤很慢,由于CPU可以同时执行多条指令(前辈们把这个叫乱序执行和推测执行),因此line4和line5也执行了。达到的效果是,CPU是知道X的值的,利用X的值,从内核页表中读取array不同页表中的值保存到rcx中,同时也把该页表加入缓存。虽然等CPU回过神来,al的值其实是拿不到的,但是加入缓存这个操作以及完成了。

因此,用户态就可以遍历array的256个页表,看看读哪个页表的时间短,就猜到了X的值。

Q2:如何复现?Here is POC.

POC下载地址:

该POC是没有绕过KASLR的版本,因此输入密码提权到root查看/proc/kallsyms中查看符号linux_proc_banner的地址,并利用meltdown漏洞从用户态读取内核中的信息。

git clone https://github.com/paboldin/meltdown-exploit
cd meltdown-exploit
make
./run.sh
# enter your password

image-20190228152544875

调试分析一下原理吧!

我们尝试使用gdb动态调试binary,发现在获取kernel指令时遇到段错误,如下图所示。这是正常的,因为正常情况下用户态无法读取内核态的数据,这恰恰是meltdown可以做到的。
image-20190301094856977

Q3:如何查看当前kernel是否收到影响?

  1. 查看KPTI是否开启,如果开启就不受meltdown影响。(直接解决方案)

    dmesg -wH | grep 'Kernel/User page tables isolation'
    

    image-20190228152143843

  2. 查看kernel version。KPTI 在2018年后在linux kernel中才正式引入。因此,如果uname -a看到linux kernel version是2018年之前的,那么也要当心了。

参考资料

  1. POC github meltdown-exploit
  2. 性能VS安全?CPU芯片漏洞攻击实战(1) - 破解macOS KASLR篇
  3. 性能VS安全?CPU芯片漏洞攻击实战(2) – Meltdown获取Linux内核数据
  4. diting0x 对POC有深入的分析 一步一步理解CPU芯片漏洞:Meltdown与Spectre
  5. CPU乱序执行和预测执行导致的安全问题 俄亥俄州立大学计算机安全实验室 https://zhuanlan.zhihu.com/p/32654221