剖析洋葱路由Tor网桥与可插拔传输(上篇) - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

剖析洋葱路由Tor网桥与可插拔传输(上篇)

41yf1sh 逆向破解 2019-12-20 09:12:10
3104339
收藏

导语:在本文中,我们将分享这项研究的更多细节。我们将主要讲解如何找到内置的Tor网桥,以及Tor浏览器如何与启用的网桥共同工作。

背景

在西弗吉尼亚州查尔斯顿举办的SecureWV 2019网络安全会议上,我和Peixue进行了一场关于“剖析洋葱路由Tor网桥和可插拔传输”的主题演讲。我们将全部研究成果分两篇文章发表。在本文中,我们将分享这项研究的更多细节。我们将主要讲解如何找到内置的Tor网桥,以及Tor浏览器如何与启用的网桥共同工作。

Tor浏览器与Tor网络

Tor浏览器是一个通过Tor网络加密层提供匿名互联网连接的工具。当用户使用Tor浏览器浏览网站时,用户的真实IP地址会被Tor网络隐藏,因此目标网站永远无法获取到真实的源IP地址。用户还可以在Tor网络中建立自己的网站,其域名以“.onion”结尾。这样一来,只有Tor浏览器可以访问该网站,而没有人知道网站所对应的真实IP地址。这也解释了为什么勒索软件制作者会要求受害者通过Tor浏览器访问.onion网站上的付款页面。Tor项目团队目前清楚这样的案例,并且在Tor项目的博客上明确指出“Tor现在正在被犯罪者滥用”。

Tor浏览器是一个开源项目,其设计基于Mozilla Firefox浏览器。用户可以从其官方网站下载源代码。Tor网络是一个覆盖全球的网络,由数千个主动运行的中继节点组成。其中,又可以分为两类中继节点——普通中继节点和网桥中继节点。普通中继节点会在Tor目录中列出,用户可以轻松通过检测的方式识别和阻止与中继节点的连接。

网桥信息是在Firefox的配置文件中定义的,因此用户可以在Tor浏览器的地址栏中输入“about:config”来进行查看,如下图所示。

在Tor浏览器中查看配置数据:

1.png

但是,网桥中继节点并没有在Tor主目录中列出,这也就意味着不能通过检测的方式阻断与这些节点的连接。接下来,我将讨论如何使用Tor浏览器中内置的功能查找这些网桥与中继节点。

要在Tor浏览器中使用网桥中继,可以选择两种方法。Tor浏览器有一些内置的网桥供用户选择。如果内置的网桥不起作用,则用户可以通过访问https://bridges.torproject.org/或发送电子邮件到bridges@bridges.torproject.org来获取其他网桥。

分析使用的平台环境

我们的分析过程,是在以下平台环境中进行的:

使用Windows 7 SP1 x32操作系统;

使用Tor 浏览器8.0版本;

使用TorLauncher 0.2.16.3浏览器扩展;

使用Torbutton 2.0.6浏览器扩展。

Tor浏览器的版本信息:

2.png

在我们进行分析的过程中,Tor浏览器在2019年10月22日推出了Tor浏览器9.0的新版本。有关该版本的更多信息,请参考本文的附录。

使用内置网桥启动Tor浏览器

我们所分析的版本中,Tor浏览器提供了四种网桥方式:obfs4、fte、meek-azure和obfs3。这些都可以称为可插拔传输(Pluggable Transports)。我们可以在下图中看到详细的配置。

在Tor网络设置中选择一个内置的网桥:

3.png

我们强烈建议选择Tor官方网站上的obfs4网桥,本文的全部分析过程均使用这种网桥。通过查看Tor浏览器建立obfs4连接时的通信量,我发现TCP会话是由obfs4proxy.exe创建的,obfs4proxy.exe是一个网桥的客户端进程。

下图展示了使用obfs4启动Tor浏览器时的进程树。如图所示,firefox.exe启动了tor.exe,然后启动了obfs4proxy.exe。进程obfs4proxy.exe位于“Tor_installation_folder\Browser\TorBrowser\Tor\PluggableTransports”目录下。最初,我认为内置的obfs4网桥应该在obfs4proxy.exe进程中进行硬编码。

使用obfs4网桥时的进程树:

4.png

在网桥进程obfs4proxy.exe中进行跟踪

我们启动调试器,将其附加到obfs4proxy.exe。随后,我在connect API上设置了一个断点,该断点通常用于建立TCP连接。通常情况下,使用逆向工程的方法就可以迅速从这个API发现IP地址和端口,但在建立与obfs4网桥的连接之前,这个API并没有被触发过。经过对进程obfs4proxy.exe的进一步分析,我了解到它换用了来自mswsock.dll的另一个API“MSAFD_ConnectEx”。

调用MSAFD_ConnectEx API:

5.png

上图展示了obfs4proxy.exe调用API mswsock.MSAFD_ConnectEx()以建立与内置obfs4网桥的TCP连接,该网桥的IP地址和端口号为192.95.36.142:443。该函数的第二个参数是指向struct sockaddr_in结构变量的指针,其中保存着IP地址和要连接的端口。随后将调用WSASend和WSARecv这两个API,以与obfs4网桥进行通信。我们注意到,OllyDbg无法识别这个API,因为它不是mswsock.dll的导出功能。在使用IDA Pro对mswsock.dll进行分析时,我们看到地址750A7842只是MSAFD_ConnectEx()的API。这里需要说明的是,“call dword ptr [ebx]”指令被用来调用obfs4proxy.exe所需的几乎所有系统API,这是一种隐藏API以防止被分析的方法。

根据我的分析,Tor使用的大多数PE文件(exe和dll文件,例如obfs4proxy.exe)似乎都是由“GCC MINGW-64w编译器”编译的,该编译器始终使用“mov [esp], ...”将参数传递给函数,而并没有使用会影响静态分析的“push...”指令。通过跟踪MSAFD_ConnectEx()中的调用堆栈流,我意识到我最初的想法是错误的,内置的IP地址和端口并没有在obfs4proxy.exe中进行硬编码,而是通过本地回环TCP连接从父进程中获取的。

Obfs4proxy.exe接收到一个obfs4网桥的IP地址和端口:

6.png

通常,从tor.exe到obfs4proxy.exe的第三个数据包中,包含一个内置的obfs4网桥的IP地址和二进制端口,如上图所示。它是一个Socks5数据包,长度为0xA字节。05 01 00 01时Socks5协议的标头,其余的数据是IP地址和二进制端口。该数据包表明它要求obfs4proxy.exe与二进制表示IP地址和端口的网桥建立连接。随后,obfs4proxy.exe对数据包进行解析,并将二进制的IP和端口转换为字符串,在我们所分析的样本中IP和端口为154.35.22.13:16815。

转向Tor.exe

Tor.exe使用来自libevent(事件通知库)中名称为libevent.dll的第三方模块来驱动Tor执行任务。Tor将大多数套接字任务(connect()、send()、recv()等)放在由libevent自动调用的事件上。在Tor.exe中以网桥IP地址和端口为关键字跟踪数据包时,我们可以在调用堆栈上下文中看到模块libevent.dll由许多返回地址。在下图中,暂停在了Tor.exe调用API ws2_32.send()以发送包含网桥IP地址和端口的数据包这一步上,类似于上图展示的接收数据包。

下图是调用堆栈窗口展示的libevent.dll的返回地址:

7.png

通过跟踪发送网桥IP地址和端口的tor.exe,我们发现了一个地方,它使用回调函数启动一个新事件,然后该回调函数发送网桥的IP地址和端口。下面的ASM代码片段展示了在tor.exe中调用libevent.event_new()的上下文。其中第二个参数是套接字句柄,第三个参数是事件动作(在这里是14H,代表着EV_WRITE和EV_PERSIST),第四个参数是回调函数(这里是sub_2833EE),第五个参数是网桥的IP地址和端口(一旦被libevent调用,就会被传递给回调函数sub_2833EE)。

下面是tor.exe中截取的ASM代码段,当前基址是00280000h。

[…]  
.text:00281C84                 mov     edx, eax
.text:00281C86                 mov     eax, [ebp+var_2C] ;
.text:00281C89                 mov     [eax+14h], edx
.text:00281C8C                 mov     eax, [ebp+var_2C] ;
.text:00281C8F                 mov     ebx, [eax+0Ch]
.text:00281C92                 call    sub_5133E0
.text:00281C97                 mov     edx, eax
.text:00281C99                 mov     eax, [ebp+var_2C]
.text:00281C9C                 mov     [esp+10h], eax       ; argument for callback function
.text:00281CA0                 mov     [esp+0Ch], offset sub_2833EE    ; the callback function
.text:00281CA8                 mov     [esp+8], 14h  ; #define EV_WRITE 0x04|#define EV_PERSIST 0x10
.text:00281CB0                 mov     [esp+4], ebx       ; socket
.text:00281CB4                 mov     [esp], edx
.text:00281CB7                 call    event_new    ; event_new(event_base, socket, event EV_READ/EV_WRITE, callback_fn, callback_args);
.text:00281CBC                 mov     edx, eax
.text:00281CBE                 mov     eax, [ebp+var_2C]
.text:00281CC1                 mov     [eax+18h], edx
[…]

通过在tor.exe中连续进行反向跟踪,我发现了一些obfs4网桥,它们都位于命令SETCONF的数据结构中,如下图所示。

SETCONF命令中的部分数据:

8.png

这里展示了命令SETCONF的数据片段,其中SETCONF是结构开始的命令名称,后面紧接着内置的网桥信息。红色标出的数据是一个称为Obfs4 Bridge的块,称为网桥配置行。每个网桥的节点都必须保存在一个网桥配置行中。这里,总共有27个这样的网桥配置行。如我们所见,网桥类型obfs4、网桥的IP地址和端口都使用了字符串格式。

至此我们知道,网桥信息也同样不是在tor.exe进程中硬编码的。那么现在,我们就遇到了另一个问题——整个SETCONF数据是从哪里来的?事实上,它是来源于firefox.exe接收到的TCP数据包,firefox.exe是tor.exe的父进程。一旦tor.exe启动,它将会打开TCP控制端口9151以接收来自firefox.exe和TCP代理端口9150的命令。我们将在下文中详细说明firefox.exe如何向其发送命令。

继续分析tor.exe,我们注意到除了命令SETCONF之外,它还支持其他命令,例如GETCONF、SAVECONF、GETINFO、AUTHENTICATE、SETEVENTS、+LOADCONF、QUIT等。Tor.exe使用一个函数来处理这些命令并转向不同的代码分支。

Tor.exe根据具体的命令来执行不同的任务。例如,SAVECONF命令将使得tor.exe将网桥信息保存到“Tor_installation_folder\Browser\TorBrowser\Tor\Data\torrc”中的文件中,SETCONF负责通知tor.exe网桥信息,然后将其传递到网桥进程以建立网桥连接。

在Firefox.exe中寻找内置网桥

Tor使用了许多回环TCP连接在进程之间传递命令,以执行其具体任务。

自3.0.1版本开始,Wireshark开始支持本地回环适配器,从而允许我们捕获回环接口上的流量,例如本地回环接口上从firefox.exe通过9151 TCP控制端口传到tor.exe的SETCONF数据包。RawCap是另一个可以使用的工具。Firefox.exe以“一个字节一个数据包”的特殊方式将命令数据包发送到tor.exe。如下图所示,展示了许多长度为1的数据包。通过对它们进行组合,可以形成完整的SETCONF命令。

Firefox.exe发送命令包:

9.png

大家可能知道,Firefox浏览器可以使用第三方开发人员开发的扩展插件来执行扩展功能。由于Tor浏览器是基于Mozilla Firefox设计的,因此它具有与Firefox相同的功能。

在9.0版本之前,Tor浏览器带有两个扩展:Torbutton和TorLauncher。它们位于“Tor_installation_folder\Browser\TorBrowser\Data\Browser\profile.default\extensions”文件夹中。相应的扩展文件是torbutton@torproject.org.xpi和tor-launcher@torproject.org.xpi,如下图所示,这些都是包含JS文件和模块的ZIP压缩包。

Tor扩展文件:

10.png

但是,自9.0版本Tor浏览器以来,这两个扩展已经被删除。相反,它们的代码和功能已经合并到Tor浏览器中。更多信息请参考最后的附录部分。

Torbutton用于设置和显示Tor设置,以及显示Tor信息,例如“关于Tor”。我们可以单击Tor浏览器工具栏上显示的Tor图标找到该功能。

TorLauncher负责根据Torbutton设置来控制Tor进程。

在Firefox的xul.dll模块中,将加载TorLauncher并执行JS代码,xul.dll是Mozilla Firefox的核心组件,也是实际上将SETCONF(在network-setting.js中实现)、GETCONF(在tl-protocol.js中实现)、GETINFO(在tl-protocol.js和torbutton.js中实现)等命令发送到tor.exe的模块。Xul.dll模块是一类JS引擎,用于解析和执行这些命令的JS代码。

现在,让我们看看启用网桥后的Tor浏览器的内部工作原理。Tor浏览器在启用网桥的状态启动后,将执行以下步骤:

1、firefox.exe加载基本配置文件,首选项定义和扩展(涉及的模块:firefox.exe、xul.dll);

2、扩展TorLauncher使用命令行中的设置运行tor.exe(涉及的模块:xul.dll);

3、用户可以随时使用Torbutton更改Tor设置(涉及的模块:xul.dll);

4、它将命令发送到tor.exe,并根据通过本地回环TCP连接来传递具体的工作方式(涉及的模块:xul.dll、tor.exe);

5、然后,tor.exe运行一个特定的网桥进程(obfs3和obfs4使用obfs4proxy.exe,fte使用fteproxy.exe,meek-azure使用terminateprocess-buffer.exe)来建立网桥通信(涉及的模块:tor.exe、网桥进程);

6、tor.exe通过本地回环TCP连接与这些网桥进程通信(涉及的模块:tor.exe、网桥进程);

7、网桥进程连接到网桥中继(涉及的模块:网桥进程)。

Tor浏览器通过本地回环接口发送命令,以控制Tor客户端的工作模式。然后,它从Tor客户端接收并解析执行命令的结果。

根据我的分析,所有obfs4网桥信息都是在大量命名的全局变量(在Firefox中称为首选项)中定义的,并存储在本地文件中。它们在firefox.exe启动时进行初始化,根据名称(由xul.dll派生)读取首选项,随后对其进行访问和使用。

出于安全考虑,我隐去了包含所有网桥类型的整个网桥信息定义集合的文件名。在我所分析的Tor浏览器版本中,共包含27个obfs4网桥、4个obfs3网桥、1个meek-azure网桥和4个fte网桥。

可插拔传输

在上述分析过程中,我们提到了一些网桥的类型,包括obfs4、obfs3、meek-azure和fte。所有这些,都统称为“可插拔传输”(Pluggable Transport,PT)。它们的主要任务是转换Tor流量,并在客户端与第一跳(Tor中继)之间进行传输。因此,PT的使用可能会使Tor流量更加难以通过审查来识别或组阻断。

Obfs4是一个功能强大且最受欢迎的PT。通常,Obfs4的第一跳都是网桥中继,没有在Tor主目录中列出。Obfs4(混淆器)是由Yawning Angel开发和维护的。这是一个使用Go语言编写的开源项目,可以在GitHub上找到。Obfs网桥有多个历史版本,包括Obfs2和Obfs3。实际上,Obfs4与历史版本差异较大,更接近于ScrambleSuit,因为Obfs4的概念就来源于Philipp Winter的ScrambleSuit协议。这也就是为什么Obfs4客户端进程还可以充当ScrambleSuit客户端的原因。

Obfs4的所有功能都由obfs4proxy.exe程序提供,该程序是Tor用户的Obfs4客户端进程。

我们已经知道,Tor浏览器是基于Firefox浏览器构建的,它使用Firefox的扩展程序为用户提供匿名互联网访问。在Tor浏览器运行后,实际上会启动firefox.exe,该文件将加载两个Tor扩展(TorLauncher和Torbutton)。随后,其中的一个扩展启动tor.exe,也就是Tor客户端进程。当在Tor网络设置中将Tor浏览器设置为启用Obfs4网桥时,tor.exe将运行喔bfs4proxy.exe。

接下来,我们将详细介绍firefox.exe、tor.exe和obfs4proxy.exe这三个组件如何相互配合。

Tor浏览器如何与Tor客户端通信

Firefox.exe进程(Tor浏览器)和tor.exe(Tor客户端)通过Tor的TCP端口侦听回环接口(127.0.0.1)以实现相互通信。

根据上文我们可以看到,firefox.exe启动了tor.exe。或者更准确地说,Firefox扩展TorLauncher启动了tor.exe,该扩展由模块xul.dll加载并解析。当它调用Windows本地API ShellExecuteExW()启动tor.exe时,会有许多命令行参数传递给tor.exe。下图展现了这些命令行参数:

11.png

可以看到,共有10个参数传递给tor.exe。为了使这一过程更加清晰,我列出了下面的表格,每行展现一个参数。其中,“...\”用来代表Tor浏览器的安装路径。

12.png

在上表中,特别标出了两个端口,分别是“+__ControlPort 9151”和“+__SocksPort "127.0.0.1:9150 IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth"”。Tor.exe将侦听回环接口(127.0.0.1)的TCP 9151和9150端口,即tor.exe使用的默认端口号。

这些默认值定义在几个本地文件中,用户可以修改两个端口的默认值。下面是本地文件中的相关代码样例:

// Proxy and proxy security
pref("network.proxy.socks", "127.0.0.1");
pref("network.proxy.socks_port", 9150);

TCP/9151端口是用于在firefox.exe和tor.exe之间交换控制命令和结果的控制端口,TCP/9150则被Tor用于提供SOCKS5代理服务,该服务在firefox.exe和tor.exe之间传递SOCKS5数据包。

下面是控制命令的示例。Firefox.exe通过TCP/9151端口发送命令GETINFO到tor.exe并询问一些信息,随后tor.exe解析该命令,并将结果从TCP/9151端口发送回firefox.exe。

GETINFO status/bootstrap-phase
 
250-status/bootstrap-phase=NOTICE BOOTSTRAP PROGRESS=0 TAG=starting SUMMARY="Starting"
250 OK

Tor在127.0.0.1:9150上执行代理功能,该功能负责在firefox.exe和tor.exe之间传输普通数据包(未经Tor加密)。下图展示了在WireShark中捕获的数据包,这里我将其分为两部分,上面是Tor SOCKS5握手,下面是数据包传输。

通过TCP/9150端口在firefox.exe和tor.exe之间的Tor SOCKS5代理数据:

13.png

上图展示了使用Tor浏览器访问https://www.google.com时的数据包。在握手过程中,firefox.exe告诉tor.exe访问的目标是SOCKS5数据包中的www.google.com。在完成SOCKS5握手后,firefox.exe开始将Google TLS客户端Hello数据包发送到tor.ee,然后在Tor客户端对数据包进行加密。随后,Google TLS服务器Hello数据包从Tor客户端被发送回去。在此之后,firefox.exe开始通过TCP/9150端口向tor.exe发送请求数据包,并从tor.exe接收响应数据包。

在Tor客户端,通过TCP/9150端口接收数据包,并完成SOCKS5握手。然后,它从firefox.exe接收正常的数据包并将其加密。将Tor加密的数据包传递到所选Tor电路中的Tor入口节点。最后,Tor出口节点对接收到的数据包进行解密,得到正常数据包(如同在firefox.exe和tor.exe之间传输的数据包),并将其发送到目标服务器。

反过来,tor.exe从Tor入口节点接收加密的数据包,然后对其解密,得到纯文本数据包,该数据包最终通过TCP/9150端口从tor.exe发送到firefox.exe。

Tor客户端如何与Obfs4客户端通信

一旦Tor客户端从Tor浏览器接收到SETCONF命令,Tor客户端(tor.exe)就会启动Obfs4客户端obfs4proxy.exe。obfs4proxy.exe在回环接口上打开一个随机的TCP端口为Tor提供Obfs4网桥服务,它通过进程间管道将TCP端口号通知其父进程tor.exe。

下面的OllyDbg截图中展示了Windows API WriteFile()上的断点是在obfs4proxy.exe将其TCP端口通知tor.exe时被触发的。我们在内存中看到,“CMETHOD obfs4 socks5 127.0.0.1:49496”是用于将TCP端口发送到Tor客户端的数据。此时随机产生的TCP端口是49496。WriteFile()的第一个参数是进程间管道的文件句柄,这次是00000100。

obfs4proxy.exe通过进程间管道将其TCP端口发送到tor.exe:

14.png

之后,tor.exe可以建立与这个TCP端口的连接,以与Obfs4客户端进行通信。Tor分别将各网桥节点发送到这个端口,每次仅发送一个网桥的信息。从下图TCPView的截图中可以看到详细过程。

Tor将Obfs4网桥发送到Obfs4proxy:

15.png

上述就是Tor浏览器(firefox.exe)通过Tor客户端(tor.exe)与Obfs4客户端(obfs4proxy.exe)通信的整个过程。在下一篇文章中,我们将说明Obfs4客户端(obfs4proxy.exe)是如何与Obfs4网桥建立连接,以及Obfs4是如何转换数据包以防止被检测的。

附录

在2019年10月下旬,发布了Tor浏览器9.0版本,该版本中删除了两个扩展(TorLauncher和Torbutton),改为由Tor浏览器执行这两个扩展原本执行的任务。实际上,在分析过程中,我发现新版本并没有删除这两个扩展的代码,而是将代码集成到了名为“omin.ja”的Firefox JAR文件中。该文件在启动时由Firefox加载并解析。后面,我们可以使用菜单“Options”-“Tor”找到Tor网络设置,如下图所示。

两个扩展的功能已经集成到Tor浏览器中:

16.png

新版本的这一更改,不会影响到Tor浏览器的工作原理。因此,即使我们的分析过程是基于旧版本8.0,但该分析针对新版本也仍然适用。

在下篇文章中,我们将重点说明Tor是如何利用Obfs4网桥逃避审查的。

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务