This repository contains a modified version of the Tor daemon that allows the operator of a hidden service to force the selection of specific relays for its introduction circuit. It also includes scripts for running an intersection attack against a self-operated hidden service for experimental and reproducibility purposes.
Step 1: Force the hidden service to use specific relays in its introduction circuit
To reproduce the experiment, the hidden service operator must first control four Tor relays that are active on the live network.
-
Locate the relays in Tor Metrics:
https://metrics.torproject.org/rs.html -
For each relay, copy the following fields:
NicknameFingerprint
-
Open the file:
src/feature/hs/hs_experiment.h -
Paste the corresponding relay fingerprints and nicknames into the following fields:
-
FORCED_INTRO_FP_HEXandFORCED_INTRO_NICK
Introduction point relay -
FORCED_MID_FP_HEXandFORCED_MID_NICK
First middle relay -
FORCED_VANGUARD_FP_HEXandFORCED_VANGUARD_NICK
Vanguard relay -
FORCED_ENTRY_FP_HEXandFORCED_ENTRY_NICK
Entry guard relay
-
Before building, install the required dependencies.
brew install automake autoconf libtool pkg-config libevent openssl@3sudo apt update
sudo apt install -y git build-essential automake libevent-dev libssl-dev zlib1g-devBuild the modified Tor daemon before running the experiment. This binary is used both by the hidden service and by a colocated Tor client running on the monitored relay.
The colocated client:
- Issues requests to trigger the introduction protocol.
- Sends control signals to the intersector plugin (
packet_logger_scripts/packet_processer.py) to construct anonymity sets and compute intersections.
./autogen.sh
./configure --disable-asciidoc # do not build manpages
make
make installStep 3: Bring the hidden service online
mkdir -p /path/to/tor-hs-data
chmod 700 /path/to/tor-hs-data3.2 Create hidden service directory
mkdir -p /path/to/hidden_service
chmod 700 /path/to/hidden_serviceDataDirectory /path/to/tor-hs-data
SocksPort 0
Log notice stdout
HiddenServiceDir /path/to/hidden_service
HiddenServiceVersion 3
HiddenServicePort 80 127.0.0.1:8080python3 -m http.server 8080 --bind 127.0.0.1/path/to/tor/src/app/tor -f /path/to/torrccat /path/to/hidden_service/hostnametorsocks curl http://<your_onion_address>Install:
packet_logger_scripts/packet_processer.py
-
EXCLUDED_IPS: previous relay IP -
Leave empty for the introduction point
-
TARGET_IP: next relay IP
Mapping:
- Introduction point → Middle1
- Middle1 → Vanguard
- Vanguard → Entry
- Entry → Hidden service
Install:
packet_logger_scripts/first_nodes/runner.sh(first 3 relays)packet_logger_scripts/last_node/runner.sh(last relay)
Behavior:
- First 3 relays: SSH to next node after convergence
- Last relay: no SSH
TOR_BIN="/opt/tor-custom/bin/tor"
TORRC="/etc/tor-client/torrc"
SOCKS="127.0.0.1:9052"
ONION_URL="http://youronion.onion"
SLEEP_SECONDS=30
# SSH CONFIG
TARGET_IP="ip"
REMOTE_USER="root"
SSH_KEY="/root/.ssh/id_ed25519"
REMOTE_SCRIPT="/exp/runner.sh"
REMOTE_LOG="/exp/runner.log"Ensure SSH access between consecutive relays.
crontab -eEvery 30 minutes:
*/30 * * * * /exp/runner.sh >> /exp/runner.log 2>&1Every hour:
0 * * * * /exp/runner.sh >> /exp/runner.log 2>&1Specific times:
0 2,10,18 * * * /exp/runner.sh >> /exp/runner.log 2>&1chmod +x /exp/runner.shpip3 install matplotlib requestspython3 produce_graphs/generate_stats_and_graphs.pyEnsure no Tor process is running before executing the script.
python3 produce_graphs/measure_introduce_time.pyModify:
TARGET_URLS→ list of onion servicesCSV_PATHCSV_PATH = "/tmp/tor_hs_timing.csv"
PROXY_CMDPROXY_CMD = ["./src/app/tor"]
Ensure the modified Tor binary is built and accessible.