2024 release

This commit is contained in:
Yuheng Yang 2024-02-01 16:12:05 -05:00
parent b7b3a02bfe
commit 604a544978
9 changed files with 125 additions and 269 deletions

View File

@ -9,4 +9,4 @@
In this lab, students implement the techniques from our group's ISCA 2022 paper `There's Always a Bigger Fish: A Case Study of a Misunderstood Timing Side Channel`. Students will begin by implementing a seemingly familiar cache-based side channel attack in Javascript, and will then be asked to reason about why this attack works. Then, students will remove a core part of the attack, but see that the code still works.
**Setup**
Students can complete this lab on their own machines. MacOS, Linux, Windows all should work. Google Chrome is required for Part 4 of this lab.
Students can complete this lab on their own machines. MacOS, Linux, Windows all should work.

View File

@ -1,185 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Website Fingerprinting Lab</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
font-family: Arial, Helvetica, sans-serif;
padding: 64px;
}
h1 {
font-size: 32px;
margin-bottom: 16px;
}
p {
margin-bottom: 8px;
}
#buttons {
margin-bottom: 16px;
}
button {
background: #fff;
border: 2px solid #3498db;
border-radius: 4px;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 16px;
margin-right: 16px;
padding: 8px 16px;
}
button.disabled {
background: #ccc;
border-color: #ccc;
color: #666;
cursor: default;
}
.trace {
margin-bottom: 16px;
}
</style>
</head>
<body>
<h1>Website Fingerprinting Lab</h1>
<div id="buttons">
<button id="collect-trace">Collect trace</button>
<button id="download-traces">Download traces</button>
</div>
<div id="traces"></div>
<script src="https://d3js.org/d3.v6.js"></script>
<script type="text/javascript">
const worker = new Worker("worker.js");
const collectTraceButton = document.getElementById("collect-trace");
const downloadTracesButton = document.getElementById("download-traces");
// Default values for when the automation script isn't being used. When
// the script is in use, these values will get overwritten.
window.trace_length = 5000;
window.using_automation_script = false;
window.recording = false;
window.traces = [];
let traceIds = [];
worker.onmessage = (e) => {
window.recording = false;
const trace = JSON.parse(e.data);
window.traces.push(trace);
if (window.using_automation_script) {
// Don't display traces when automation script is in use
return;
}
// Create new trace div
const parent = document.getElementById("traces");
const div = document.createElement("div");
const traceId = "a" + Math.random().toString().substring(2, 10);
div.setAttribute("id", traceId);
div.className = "trace";
parent.appendChild(div);
traceIds.push(traceId);
// Trace dimensions
const width = parent.getBoundingClientRect().width;
const height = 64;
// Create div for new trace
const svg = d3
.select("#" + traceId)
.append("svg")
.attr("width", width)
.attr("height", height);
// Find largest value across all traces
const maxVal = d3.max(window.traces, (d) => d3.max(d));
for (let i = 0; i < window.traces.length; i++) {
// Re-visualize all traces each time in case maxVal changes
const x = d3
.scaleLinear()
.domain([0, window.traces[i].length])
.range([0, width]);
const color = d3
.scaleQuantize()
.range(["#0d0887", "#7e03a8", "#cc4778", "#f89540", "#f0f921"])
.domain([0, maxVal]);
svg
.selectAll()
.data(window.traces[i].map((x, i) => ({ index: i, value: x })))
.join("rect")
.attr("x", (d) => x(d.index))
.attr("y", 0)
.attr("width", x(1))
.attr("height", height)
.style("fill", (d) => color(d.value));
}
// Reset UI
collectTraceButton.innerText = "Collect trace";
collectTraceButton.className = "";
};
function collectTrace() {
collectTraceButton.innerText = "Collecting trace...";
collectTraceButton.className = "disabled";
window.recording = true;
worker.postMessage({
type: "start",
trace_length: window.trace_length,
});
}
collectTraceButton.onclick = () => {
if (window.recording) return;
window.recording = true;
collectTraceButton.innerText = "Starting in 3...";
collectTraceButton.className = "disabled";
setTimeout(() => {
collectTraceButton.innerText = "Starting in 2...";
setTimeout(() => {
collectTraceButton.innerText = "Starting in 1...";
setTimeout(collectTrace, 1000);
}, 1000);
}, 1000);
};
downloadTracesButton.onclick = () => {
const blob = new Blob([JSON.stringify({ traces: window.traces })], {
type: "application/json",
});
const url = URL.createObjectURL(blob);
const elem = document.createElement("a");
elem.href = url;
elem.download = "traces.json";
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);
};
</script>
</body>
</html>

View File

@ -1,7 +1,7 @@
const runs = 10;
function measureOneLine() {
const LINE_SIZE = 16; // 64/sizeof(int)
const LINE_SIZE = 32; // 128/sizeof(int)
let result = [];
// Fill with -1 to ensure allocation

View File

@ -6,22 +6,22 @@ from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
def eval():
y_pred_full, y_test_full = [], []
y_pred_full, y_test_full = [], []
# Re-train 10 times in order to reduce effects of randomness
for i in range(10):
### TODO: Exercise 2-4
### 1. Load data from traces file
### 2. Split data into X_train, X_test, y_train, y_test with train_test_split
### 3. Train classifier with X_train and y_train
### 4. Use classifier to make predictions on X_test. Save the result to a variable called y_pred
# Re-train 10 times in order to reduce effects of randomness
for i in range(10):
### TODO: Exercise 2-5
### 1. Load data from traces file
### 2. Split data into X_train, X_test, y_train, y_test with train_test_split
### 3. Train classifier with X_train and y_train
### 4. Use classifier to make predictions on X_test. Save the result to a variable called y_pred
# Do not modify the next two lines
y_test_full.extend(y_test)
y_pred_full.extend(y_pred)
# Do not modify the next two lines
y_test_full.extend(y_test)
y_pred_full.extend(y_pred)
### TODO: Exercise 2-4 (continued)
### 5. Print classification report using y_test_full and y_pred_full
### TODO: Exercise 2-5 (continued)
### 5. Print classification report using y_test_full and y_pred_full
if __name__ == "__main__":
eval()
eval()

View File

@ -1,6 +1,6 @@
// Number of sweep counts
// TODO: Choose an appropriate value!
let P;
// TODO (Exercise 2-1): Choose an appropriate value!
let P = 1000;
// Number of elements in your trace
let K = 5 * 1000 / P;
@ -21,7 +21,7 @@ function record() {
// Save start timestamp
start = performance.now();
// TODO: Record data for 5 seconds and save values to T.
// TODO (Exercise 2-1): Record data for 5 seconds and save values to T.
// Once done recording, send result to main thread
postMessage(JSON.stringify(T));

View File

@ -6,22 +6,22 @@ from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
def eval():
y_pred_full, y_test_full = [], []
y_pred_full, y_test_full = [], []
# Re-train 10 times in order to reduce effects of randomness
for i in range(10):
### TODO: Exercise 5
### 1. Load data from traces file
### 2. Split data into X_train, X_test, y_train, y_test with train_test_split
### 3. Train classifier with X_train and y_train
### 4. Use classifier to make predictions on X_test. Save the result to a variable called y_pred
# Re-train 10 times in order to reduce effects of randomness
for i in range(10):
### TODO: Exercise 2-5
### 1. Load data from traces file
### 2. Split data into X_train, X_test, y_train, y_test with train_test_split
### 3. Train classifier with X_train and y_train
### 4. Use classifier to make predictions on X_test. Save the result to a variable called y_pred
# Do not modify the next two lines
y_test_full.extend(y_test)
y_pred_full.extend(y_pred)
# Do not modify the next two lines
y_test_full.extend(y_test)
y_pred_full.extend(y_pred)
### TODO: Exercise 5 (continued)
### 5. Print classification report using y_test_full and y_pred_full
### TODO: Exercise 2-5 (continued)
### 5. Print classification report using y_test_full and y_pred_full
if __name__ == "__main__":
eval()
eval()

View File

@ -1,6 +1,6 @@
// Number of sweep counts
// TODO: Choose an appropriate value!
let P;
// TODO (Exercise 3-1): Choose an appropriate value!
let P = 1000;
// Number of elements in your trace
let K = 5 * 1000 / P;
@ -21,7 +21,7 @@ function record() {
// Save start timestamp
start = performance.now();
// TODO: Record data for 5 seconds and save values to T.
// TODO (Exercise 3-1): Record data for 5 seconds and save values to T.
// Once done recording, send result to main thread
postMessage(JSON.stringify(T));

89
report.md Normal file
View File

@ -0,0 +1,89 @@
## Optional
**Report your browser version, CPU type, cache size, RAM amount, and OS. We use this information to learn about the attacks behavior on different machines.**
- Browser:
- CPU:
- Cache sizes:
- RAM:
- OS:
## 1-2
**Use the values printed on the webpage to find the median access time and report your results as follows.**
| Number of Cache Lines | Median Access Latency (ms) |
| --------------------- | -------------------------- |
| 1 | |
| 10 | |
| 100 | |
| 1,000 | |
| 10,000 | |
| 100,000 | |
| 1,000,000 | |
| 10,000,000 | |
## 1-3
**According to your measurement results, what is the resolution of your `performance.now()`? In order to measure differences in time with `performance.now()``, approximately how many cache accesses need to be performed?**
## 2-2
**Report important parameters used in your attack. For each sweep operation, you access N addresses, and you count the number of sweep operations within a time interval P ms. What values of N and P do you use? How do you choose N? Why do not you choose P to be larger or smaller?**
## 2-3
**Take screenshots of the three traces generated by your attack code and include them in the lab report.**
![Screenshot of traces](./part2/Screenshot.png)
## 2-4
**Use the Python code we provided in Part 2.1 to analyze simple statistics (mean, median, etc.) on the traces from google.com and nytimes.com. Report the statistic numbers.**
## 2-6
**Include your classification results in your report.**
```
```
## 3-2
**Include your new accuracy results for the modified attack code in your report.**
```
```
## 3-3
**Compare your accuracy numbers between Part 2 and 3. Does the accuracy decrease in Part 3? Do you think that our “cache-occupancy” attack actually exploits a cache side channel? If not, take a guess as to possible root causes of the modified attack.**

View File

@ -1,48 +0,0 @@
#!/bin/bash
# Updates repository to latest starter code
#
# Adapted from Oliver Beckstein's ASU-CompMethodsPhysics-PHY494 course 2016-2020 placed into the public domain
# With GitHub template repositories one needs to use --allow-unrelated-histories
# at least once. https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template
progname="$0"
REMOTE_NAME="startercode"
REMOTE_URL="https://github.com/CSAIL-Arch-Sec/SHD-WebsiteFingerprintingLab.git"
# progname, from top dir
UPDATESH="./deploy/$(basename $progname)"
CONTACT_MESSAGE="Contact the instructor and TA with a screen shot of ALL output from running $0."
function die () {
local msg="$1" err=${2:-1}
echo "ERROR: ${msg}."
exit $err
}
# ensure everything relative to top dir
topdir="$(git rev-parse --show-toplevel)" || die "Failed to get rootdir"
cd "${topdir}" || die "Failed to get to the git root dir ${rootdir}"
# first time
# 1. set remote repo
# 2. merge histories between student (template) and remote skeleton
if ! git remote get-url ${REMOTE_NAME} >/dev/null 2>&1; then
echo "Adding remote repository '${REMOTE_NAME}'."
git remote add ${REMOTE_NAME} ${REMOTE_URL}
echo "Merging histories for the first time..."
set -x
git pull --allow-unrelated-histories -s recursive -X theirs --no-edit ${REMOTE_NAME} main || \
{ git rev-list -1 MERGE_HEAD >/dev/null 2>&1 && git merge --abort ; \
git remote rm ${REMOTE_NAME}; \
die "Failed to merge histories. ${CONTACT_MESSAGE}" $?; }
set +x
fi
echo "updating repository... git pull from ${REMOTE_NAME}"
git pull --no-edit ${REMOTE_NAME} main || die "Failed to pull from ${REMOTE_NAME}. ${CONTACT_MESSAGE}"