Tor 的电路填充框架
填充机是一种存在于每个电路中的状态机,因此被称为 "电路填充框架"。填充机器注入虚假(填充)单元,目的各有不同,例如向被动网络对手隐藏电路的目的(例如区分 "常规 "电路和洋葱服务)。
circuitpadding.h 是自下而上的,因此要回答什么是机器,我们在这里更多地是自上而下的。机器有三个主要结构:
- circpad_machine_spec_t 机器的全局规范,不可变。
- circpad_state_t 全局不可变的状态描述,以及作为机器一部分的可能转换。
- circpad_machine_runtime_t 状态机当前状态的每个电路描述,包含可变数据,尽可能小,以减少内存使用。
因此,一台机器由一个 circpad_machine_spec_t 组成,它指定了若干状态及其转换(circpad_state_t),所有状态均不可变。对于每个电路,一个 circpad_machine_runtime_t 包含可变数据,例如电路上机器的当前状态。
circpad_machine_spec_t详细信息
最重要的字段是条件和状态,states 是一个状态数组,最大大小为CIRCPAD_STATENUM_MAX,目前为 UINT16_MAX,为状态提供了足够的空间(作为比较,WTF-PAD 有三个状态)。
circpad_state_t详细信息
- IAT 直方图或概率分布。
- 为 IAT 使用 RTT 估计值的标志。
- 具有最小-最大参数的长度(以发送(填充)单元数为单位)概率分布。
- 导致从当前状态过渡到相同或其他状态的事件数组。
circpad_machine_sample_delay() 使用 IAT 直方图/分布来采样调度单个填充单元的延迟(以微秒为单位)。作为参考,调整直方图是 WTF-PAD 防御的难点问题,也是电路填充框架设计的灵感来源。
circpad_machine_runtime_t详细信息
运行时结构体包含大量用于内部记账的变量,涉及计时器、当前状态、直方图(如果使用)、发送的填充量等。据我所知,这些变量在创建机器时都是透明的。
从零开始构建padding machine
本文档描述了在tor的新电路填充框架中从头开始构建“填充机”的过程。 将早期自适应填充 (APE) 从 basket2 移植到电路填充框架的过程中记下了注释。 我们的目标只是记录整个过程并提供有用的指导,而不是创建一个有用的机器。
- 克隆并编译
- 在 Tor浏览器中使用新建的 Tor,并在我们运行的小型(非出口)中继中使用
- 添加一个简单的 APE 填充机
- 运行机器,检查活动日志
- 端口 APE 的状态机,无需考虑太多参数
1.克隆并编译
git clone https://git.torproject.org/tor.git cd tor git checkout tor-0.4.1.5
上面使用了 tor-0.4.1.5 的标签,其中发布了电路填充框架,请随意使用更新的东西(尽管避免 HEAD,可能会有错误)。
sh autogen.sh
./configure
make
当运行 ./configure 时,会被告知缺少在基于 debian 的发行版上安装的依赖项和软件包。 重要提示:如果您计划在中继上运行 Tor 作为真实 Tor 网络的一部分,并且您的服务器运行使用 systemd 的发行版,那么建议
apt install dpkg dpkg-dev libevent-dev libssl-dev asciidoc quilt dh -apparmor libseccomp-dev dh-systemd libsystemd-dev pkg-config dh-autoreconf libfakeroot zlib1g zlib1g-dev automake liblzma-dev libzstd-dev
并确保 Tor 已启用 systemd 支持:
./configure --enable-systemd
如果没有这个,在最近的 Ubuntu 上,我的 tor 服务每五分钟就会被 systemd 强制重新启动(SIGINT 中断)。如果您想在本地系统上安装,请运行 make install。 对于我们的例子,我们只需要 src/app/tor 中的 tor 二进制文件。
2.在 Tor 浏览器和中继中使用 Tor
从 torproject.org 下载并安装新的 Tor 浏览器 (TB)。 确保它有效。 从命令行,相对于提取 TB 时创建的文件夹,运行./Browser/start-tor-browser --verbose 以获取一些基本日志输出。 请注意 Tor 的版本,在我的例子中,Tor 0.4.0.5 (git-bf071e34aa26e096) 作为 TB 8.5.4 的一部分。 关闭 TB,复制您之前编译的 tor 二进制文件并替换 Browser/TorBrowser/Tor/tor。 再次从命令行启动 TB,您应该看到不同的版本,在我的例子中是 Tor 0.4.1.5 (git-439ca48989ece545)。
我们运行的relay也是在linux上,tor位于/usr/bin/tor。 要查看自上次启动以来的相关日志,请执行 sudo Journalctl -b /usr/bin/tor,其中我们发现 Tor 0.4.0.5 在 Linux 上运行。 将本地编译的 tor 复制到中继的临时位置,然后确保其所有权和访问权限与 /usr/bin/tor 相同。 接下来,使用 sudo service tor stop 关闭正在运行的 tor 服务,等待其停止(通常为 30 秒),复制我们本地编译的 tor 替换 /usr/bin/tor 然后再次启动该服务。 检查我们看到的日志或 0.4.1.5 (git-439ca48989ece545)。
{反复关闭中继对网络有害,应避免。 对于那个很抱歉。}
在继续操作机器之前,我们还剩下一步:配置 TB 以始终使用我们的中间继电器。 编辑 Browser/TorBrowser/Data/Tor/torrc 并设置 MiddleNodes <fingerprint>,其中 <fingerprint> 是中继的指纹。 启动TB,访问一个网站,通过查看电路显示手动确认中间是否被使用。
3.添加一台简单的 APE 填充机
现在是有趣的部分。 我们有多种资源可供使用(请注意,链接将来可能会损坏,只需搜索标题即可):
- 官方电路填充开发人员文档。
- 我们对电路填充框架的实现做了注释。
- Tor 中当前电路填充机的实现:CircuitPadding.c 和 CircuitPadding_machines.h。
详情请参阅上述链接。 展望未来,重点是描述所做的事情,而不一定解释所有细节。
由于我们计划对 tor 进行更改,因此创建一个新分支。
git checkout -b circuit-padding-ape-machine tor-0.4.1.5
我们首先在 circuitpadding_machines.h 中声明两个函数,一个用于客户端的机器,一个用于中继:
void circpad_machine_relay_wf_ape(smartlist_t *machines_sl);
void circpad_machine_client_wf_ape(smartlist_t *machines_sl);
定义进入 circuitpadding_machines.c:
/**************** Adaptive Padding Early (APE) machine ****************/
/**
* Create a relay-side padding machine based on the APE design.
*/
void
circpad_machine_relay_wf_ape(smartlist_t *machines_sl)
{
circpad_machine_spec_t *relay_machine
= tor_malloc_zero(sizeof(circpad_machine_spec_t));
relay_machine->name = "relay_wf_ape";
relay_machine->is_origin_side = 0; // relay-side
// Pad to/from the middle relay, only when the circuit has streams
relay_machine->target_hopnum = 2;
relay_machine->conditions.min_hops = 2;
relay_machine->conditions.state_mask = CIRCPAD_CIRC_STREAMS;
// limits to help guard against excessive padding
relay_machine->allowed_padding_count = 1;
relay_machine->max_padding_percent = 1;
// one state to start with: START (-> END, never takes a slot in states)
circpad_machine_states_init(relay_machine, 1);
relay_machine->states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
CIRCPAD_STATE_END;
// register the machine
relay_machine->machine_num = smartlist_len(machines_sl);
circpad_register_padding_machine(relay_machine, machines_sl);
log_info(LD_CIRC,
"Registered relay WF APE padding machine (%u)",
relay_machine->machine_num);
}
/**
* Create a client-side padding machine based on the APE design.
*/
void
circpad_machine_client_wf_ape(smartlist_t *machines_sl)
{
circpad_machine_spec_t *client_machine
= tor_malloc_zero(sizeof(circpad_machine_spec_t));
client_machine->name = "client_wf_ape";
client_machine->is_origin_side = 1; // client-side
/** Pad to/from the middle relay, only when the circuit has streams, and only
* for general purpose circuits (typical for web browsing)
*/
client_machine->target_hopnum = 2;
client_machine->conditions.min_hops = 2;
client_machine->conditions.state_mask = CIRCPAD_CIRC_STREAMS;
client_machine->conditions.purpose_mask =
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_GENERAL);
// limits to help guard against excessive padding
client_machine->allowed_padding_count = 1;
client_machine->max_padding_percent = 1;
// one state to start with: START (-> END, never takes a slot in states)
circpad_machine_states_init(client_machine, 1);
client_machine->states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
CIRCPAD_STATE_END;
client_machine->machine_num = smartlist_len(machines_sl);
circpad_register_padding_machine(client_machine, machines_sl);
log_info(LD_CIRC,
"Registered client WF APE padding machine (%u)",
client_machine->machine_num);
}
我们还必须修改 circuitpadding.c 中的 circpad_machines_init() 来注册我们的机器:
/* Register machines for the APE WF defense */
circpad_machine_client_wf_ape(origin_padding_machines);
circpad_machine_relay_wf_ape(relay_padding_machines);
我们运行 make 来获取新的 Tor 二进制文件并将其复制到本地 TB。
4.运行机器
为了能够在启动 TB 时在控制台中查看电路信息事件,我们将 Log [circ]info notice stdout添加到 TB 的 torrc 中。
运行TB访问example.com我们首先在日志中发现:
Aug 30 18:36:43.000 [info] circpad_machine_client_hide_intro_circuits(): Registered client intro point hiding padding machine (0)
Aug 30 18:36:43.000 [info] circpad_machine_relay_hide_intro_circuits(): Registered relay intro circuit hiding padding machine (0)
Aug 30 18:36:43.000 [info] circpad_machine_client_hide_rend_circuits(): Registered client rendezvous circuit hiding padding machine (1)
Aug 30 18:36:43.000 [info] circpad_machine_relay_hide_rend_circuits(): Registered relay rendezvous circuit hiding padding machine (1)
Aug 30 18:36:43.000 [info] circpad_machine_client_wf_ape(): Registered client WF APE padding machine (2)
Aug 30 18:36:43.000 [info] circpad_machine_relay_wf_ape(): Registered relay WF APE padding machine (2)
一切顺利,我们的机器正在运行。 进一步观察我们发现:
Aug 30 18:36:55.000 [info] circpad_setup_machine_on_circ(): Registering machine client_wf_ape to origin circ 2 (5)
Aug 30 18:36:55.000 [info] circpad_node_supports_padding(): Checking padding: supported
Aug 30 18:36:55.000 [info] circpad_negotiate_padding(): Negotiating padding on circuit 2 (5), command 2
Aug 30 18:36:55.000 [info] circpad_machine_spec_transition(): Circuit 2 circpad machine 0 transitioning from 0 to 65535
Aug 30 18:36:55.000 [info] circpad_machine_spec_transitioned_to_end(): Padding machine in end state on circuit 2 (5)
Aug 30 18:36:55.000 [info] circpad_circuit_machineinfo_free_idx(): Freeing padding info idx 0 on circuit 2 (5)
Aug 30 18:36:55.000 [info] circpad_handle_padding_negotiated(): Middle node did not accept our padding request on circuit 2 (5)
我们看到我们的中间支持填充(自从我们升级到 tor-0.4.1.5),我们尝试协商,我们的机器在客户端上启动,转换到最终状态,然后被释放。 最后一行表明中间没有可以运行的垫料机。
接下来,我们遵循与之前相同的步骤,并在中间中继处替换修改后的 tor。 我们不会更新那里的日志记录,以避免登录实时网络上的信息级别。 再次查看客户端日志,我们发现协商工作与以前一样,除了最后一行:它丢失了,因此机器也在中间运行。
5.实现 APE 状态机
移植相当简单:定义所有机器的状态,再添加两台机器(用于 WTFP-PAD 的接收部分,超出 AP),并为分布选择合理的参数(我现在完全控制它,就像实现 APE 时一样)。 circuit-padding-ape-machine 分支包含完整机器的提交以及大量评论。
对这个过程的一些评论:
- tor-0.4.1.5 不支持同一线路上的两台机器,必须进行以下修复:https://trac.torproject.org/projects/tor/ticket/31111 。 好消息是,在修复程序进行微小更改后,其他一切似乎都有效。
- APE 随机化其分布。 目前,这只能在 Tor 启动期间完成。 这在审查规避设置 (obfs4) 中有意义,但对于 WF 防御来说意义不大:进一步随机化每个电路可能对攻击者来说是一个 PITA,几乎没有什么缺点。
- 令人烦恼的是,我编译的 Tor 中缺乏 systemd 支持导致 systemd 每五分钟在中间中继中断(SIGINT)我的 Tor 进程。 更新了上面的构建步骤,希望可以减轻其他人的痛苦。
- 当过早发送填充单元时,中继肯定存在一些错误(?)。 由于 circpad_machine_relay_wf_ape_send(),APE 实现中可能会发生这种情况。 接下来会调查。
- 正如电路填充文档草案中所建议的那样,将机器的注册从机器的定义移动到 circpad_machines_init() 是有意义的。
请记住,APE 只是一个概念验证,我们对其抵御 WF 攻击的能力做出零声明,特别是基于深度学习的攻击。
如何收集大量痕迹
基本使用 python、shell 脚本和容器。 这个想法是在容器中运行许多无头 Tor 浏览器客户端,这些客户端反复从收集服务器获取工作。 该作品由一个可访问的 URL 组成。 当访问 URL 时,客户端会记录其 Tor 日志并将其上传到服务器。
修改 Tor 浏览器
首先从 torproject.org 下载此文件夹和全新的 Linux Tor 浏览器安装。 编辑 Browser/start-tor-browser,第 12 行,将其更改为:
if [ "x$DISPLAY" = "x" ] && [[ "$*" != *--headless* ]]; then
这使得在无头模式下运行 Tor 浏览器成为可能,而无需完整的 X 安装。
无头模式下的 Tor 浏览器不会显示 Tor 启动器启动提示,并且会无限期挂起。 要跳过提示,请在 TB 附带的 Firefox 配置文件中创建一个首选项文件:Browser/TorBrowser/Data/Browser/profile.default/user.js,并添加以下一行:
user_pref("extensions.torlauncher.prompt_at_startup", false);
编辑 Browser/TorBrowser/Data/Tor/torrc 并设置任何必要的限制,例如 EntryNodes、MiddleNodes 或 UseEntryGuards,具体取决于要运行的实验。 如果您使用的是 Circuitpadding 模拟器(下面有详解),请构建自定义 tor 二进制文件,将其添加到位于 Browser/TorBrowser/Tor/ 的 TB,并将“Log [circ]info notification stdout”添加到 torrc。
当我们收集 Goodenough 数据集的踪迹时,我们使用了以下 torrc:
Log [circ]info notice stdout
UseEntryGuards 0
Circuit Padding Simulator
Tor电路填充框架中填充机器的最小模拟器。由两个存储库组成。 该存储库包含 python 粘合代码,可从 Tor 日志文件中提取跟踪并合成新的跟踪。电路填充模拟器由两个存储库组成。 该存储库包含 python 粘合代码,可从 Tor 日志文件中提取跟踪并合成新的跟踪。此外,它还提供了一个单元测试,可以获取输入跟踪文件并对它们应用电路填充机,从而生成受保护的跟踪。将这两部分结合在一起,您的 Tor 客户端和 Tor 中继可以记录未防御(非填充)的跟踪,然后将填充机应用于这些跟踪,从而在模拟中或在实时 Tor 网络上生成受防御的跟踪。
快速入门和测试示例
假设您已在名为 circpad-sim 的目录中签出此存储库,并且您当前位于该目录中,则执行以下操作:
cd .. # from circpad-sim checkout, go up
git clone https://github.com/mikeperry-tor/tor.git
cd tor
git checkout -t origin/circpad-sim-v4 # Adjust origin and branches as needed
然后像平常一样构建tor。 模拟器作为 tor 单元测试框架的一部分进行测试,您可以按如下方式检查:
./src/test/test circuitpadding_sim/..
circuitpadding_sim/circuitpadding_sim_main: [forking] OK
1 tests ok. (0 skipped)
构建docker容器
1. 在要用于收集的计算机上,安装 docker。
2. 在 docker-debian 或 docker-ubuntu 中构建 Dockerfile,具体取决于构建自定义 tor 二进制 的环境。 您可以通过运行以下命令来构建容器: docker build -t wf-collect . (注意点)。
启动容器
在每台机器上:
1. 将您之前修改的 tor-browser_en-US 复制到 exp 中。
2. 运行./set_tb_permissions.sh。
编辑 run.sh 然后运行它。
在我们的实验中,我们创建了三个具有不同安全级别/设置的 Tor 浏览器 zip 文件,并将它们全部放在 exp 文件夹中。 然后我们使用以下命令在每台机器上轮换:
rm -rf collect/exp/tor-browser_en-US && cd collect/exp/ && unzip tor-browser_en-US-safest.zip && cd ../ && ./set_tb_permissions.sh && ./run.sh
设置采集服务器
在可以从 docker 容器访问的服务器上运行 circpad-server.py。 该脚本的参数很大程度上是不言自明的:
usage: circpad-server.py [-h] -l L -n N -d D [-m M] [-s S]
optional arguments:
-h, --help show this help message and exit
-l L file with list of sites to visit, one site per line
-n N number of samples
-d D data folder for storing results
-m M minimum number of lines in torlog to accept
-s S stop collecting at this many logs collected, regardless of
remaining sites or samples (useful for unmonitored sites)
所有客户端都将尝试从服务器获取工作,如果失败,则在重试之前休眠指定的超时时间(默认值:60 秒)。 在我们的实验中,我们使用了 7 台带有 20 个容器的机器,每台机器都与具有单个适度核心的服务器进行通信,没有太多麻烦。 所有机器,包括服务器,都位于同一个集群中。 在单独的物理机器上运行服务器可能意味着由于单线程,服务器在收集过程中成为太大的瓶颈。
从数据集中提取痕迹
收集原始数据集后,下一步是提取有用的日志并获取一些 circpad 跟踪。 extract 文件夹包含您需要的所有内容:extract.py 脚本将验证日志是否包含访问预期网站的痕迹,并按照我们的 Goodenough 数据集构建数据集。
usage: extract.py [-h] -i I -o O -t T -l L [--monitored] [--unmonitored]
[-c C] [-s S] [-m M]optional arguments:
-h, --help show this help message and exit
-i I input folder of logs
-o O output folder for logs
-t T output folder for traces
-l L file with list of sites to visit, one site per line
--monitored extract monitored
--unmonitored extract unmonitored
-c C the number of monitored classes
-s S the number of samples
-m M minimum number of lines in a trace
有关如何使用 extract.py 的示例,请参阅 helper all.sh 脚本。