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

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

41yf1sh 逆向破解 2019-12-23 10:09:12
34024605
收藏

导语:在本文中,我将继续说明Tor如何利用Obfs4网桥来绕过审查。

背景

这是系列文章中的下篇,在上篇文章中,我详细介绍了Tor浏览器的内置网桥如何通过三个进程(firefox.exe、tor.exe和obfs4proxy.exe)工作的,以及Tor浏览器如何与Obfs4网桥客户端进行通信的,最后还介绍了这三个进程之间的关系。在本文中,我将继续说明Tor如何利用Obfs4网桥来绕过审查。

使用Tor时的流量:使用/不使用Obfs4网桥

在讨论Obfs4网桥之前,我想首先解释一下启用Obfs4网桥的Tor浏览器与未启用的浏览器之间的区别。为了清楚易懂,我绘制了两个Tor流量图,如下所示。

未使用Obfs4网桥的正常Tor流量:

1.png

这里展示了未使用Obfs4网桥的正常Tor通信流。我们将这一过程简短描述如下:Tor客户端从Tor主目录中获得三个Tor中继,分别是入口节点、中继节点和出口节点。一旦用户访问网站,Tor客户端就会从Tor浏览器(firefox.exe)接收请求数据包。然后,会使用来自出口节点、中继节点和入口节点的会话密钥,对这个数据包进行三次加密。然后,将多重加密后的数据包发送到入口节点、中继节点和出口节点。在经过解密后,出口中继会得到原始数据包,并将其发送到目标服务器,例如www.google.com。这就是Tor将原始数据包从Tor浏览器传输到目标网站的方式。

但是,通过检查,很容易识别并阻断Tor加密的流量(如上图的红色箭头所示)。

使用Obfs4网桥的Tor流量:

2.png

这里展示了使用Obfs4网桥后新的通信路径。我们可以清楚看到,一旦启用了Obfs4网桥,Tor流量就会发送到Obfs4客户端(obfs4proxy.exe)进行转换后再传输到网桥中继。这里的网桥中继是入口节点,而不是以前Tor的入口节点。为了保证良好的性能,任何特定的Tor电路的节点总数始终为3。

Obfs4网桥客户端获取Tor加密的Payload,并使用Obfs4函数对其进行封装。然后将封装的数据包发送到Obfs4网桥中继。在对其解封装之后,网桥中继会得到Tor加密后的数据包,并将其转发到Tor电路的下一个Tor中继,反之同理。

我们简单地讲解了Obfs4网桥的工作过程。接下来,我们将讨论Obfs4网桥使用哪些技术来保证流量难以识别。

SETCONF命令和网桥控制行

Tor浏览器(firefox.exe)通过控制TCP/9151端口,将带有内置Obfs4网桥信息的SETCONF命令发送到tor.exe,该命令类似于如下格式:

SETCONF UseBridges=1 Bridge="obfs4 109.105.109.165:10527
8DFCD8FB3285E855F5A55EDDA35696C743ABFC4E
cert=Bvg/itxeL4TWKLP6N1MaQzSOC6tcRIBv6q57DYAZc3b2AzuM+/TfB7mqTFEf
XILCjEwzVA iat-mode=1" Bridge="obfs4 85.17.30.79:443 ……

最开始的“SETCONF”是命令名称,“UseBridges=1”表示Tor用户已经启用网桥功能。后面的数据包括完整的内置Obfs4网桥块,在Tor网站上被称为“网桥配置行”(Bridge Configuration Lines)。在这里,我们仅以第一个网桥配置行为例。每个网桥配置行都是以“Bridge=”开头,其中包括:

网桥类型:obfs4,表示具体的网桥类型;

网桥服务器IP地址和端口:109.105.109.165:10527;

网桥ID:14H长的十六进制;

网桥证书:Obfs4中继经过Base64编码的nodeID和IDPublicKey;

网桥IAT模式:IAT模式标志可以设置为0、1或2。

Tor将处理这一命令,然后启动obfs4proxy子进程,也就是Obfs4网桥客户端。Obfs4proxy.exe使用相同的过程,通过Obfs4网桥客户端和Tor客户端之间的回环接口上的TCP端口来传输数据包。

Tor客户端与Obfs4客户端进行通信

Tor客户端分别将Obfs4网桥发送到obfs4proxy.exe,并要求其与Obfs4网桥中继建立连接。Tor使用SOCKS5协议通过Obfs4网桥客户端传输数据。

Tor.exe将一个Obfs4网桥信息实例发送到obfs4proxy.exe:

3.png

上图是使用WireShark抓取到的tor.exe与obfs4proxy.exe之间通信数据包的截图。红色的数据包代表从tor.exe到obfs4proxy.exe(通过回环接口上的随机TCP端口)的流量,而响应数据包标记为蓝色。我们可以看到,这里还使用了SOCKS5协议。

首先,将包含Base64编码的“cert=”和IAT模式的Obfs4网桥信息从tor.exe发送到obfs4proxy.exe。然后,tor.exe继续以SOCKS5“Connect (1)”数据包(以“|05 01 00 01|”开头)发送Obfs4网桥中继的二进制IP地址和端口。然后,使用IP地址和端口将obfs4proxy.exe连接到该网桥中继。成功建立连接后,将“Succeeded (0)”数据包(“|05 00 00 01 00 00 00 00 00 00|”)发送回tor.exe。这意味着,Obfs4握手已经成功进行(我们将在下一章详细讲解握手过程)。之后,tor.exe可以通过这个连接发送和接收需要由Obfs4网桥转换和传输的所有数据包。

Obfs4客户端与Obfs4网桥开始握手

要连接Obfs4网桥,需要一个握手过程,其目的是传输公钥并进行相互验证。

在对握手数据包进行分析之前,我们首先花一些时间来讨论Obfs4使用的加密算法和密钥对(Keypair)的结构。

Obfs4网桥使用ECC(椭圆曲线加密)算法对Tor Payload进行加密,以确保Obfs4客户端和中继之间的安全通信。众所周知,ECC是一个基于椭圆曲线理论的公钥加密技术。Obfs4使用的ECC在名为“curve25519”的Go语言包中实现,该包提供了两个重要的函数,分别是ScalarBaseMult()和ScalarMult()。

下面是密钥对结构的定义,其主要功能是保存公钥和私钥:

// Keypair is a Curve25519 keypair with an optional Elligator representative.
// As only certain Curve25519 keys can be obfuscated with Elligator, the
// representative must be generated along with the keypair.
 
type Keypair struct {
     public     *PublicKey
     private    *PrivateKey
     representative *Representative
}

客户端和服务器都必须具有自己的密钥对实例。我们来分析一下二者之间的关系。根据curve25519软件包中的定义,会在一定范围内随机生成私钥。每个ECC通过调用curve25519.ScalarBaseMult()根据私钥计算出公钥。然后,将其从公钥转换为代表密钥(Representative Key),也可以在需要时通过调用函数extra25519.RepresentativeToPublicKey()来轻松还原成公钥。这一密钥对的定义和初始化是在源文件ntor.go中定义的NewKeypair()函数中实现的。

客户端和服务器各自保存其自己的私钥,并以代表密钥的形式相对方发送公钥。

Obfs4客户端发出握手数据包以启动连接过程,因此我们来分析一下客户端握手数据包。数据包结构如下:

4.png

在客户端的握手数据包中,第一部分是Keypair.representative,其长度为20h字节。在服务器端,它可以作为还原客户端的公钥。

第二部分是使用随机字节的填充数据,其数据大小范围在4Dh至1FC0h之间,该填充数据会混淆握手数据包的大小,从而使其更难识别。

第三部分在Obfs4源代码中被称为“mark”,它是第一部分Keypair.representative的HMAC值。Obfs4使用SHA-256生成HMAC,长度为20h字节。Obfs4仅将前10h字节保留为HMAC,其余10h字节将被丢弃。

Obfs4使用当前系统时间来计算UNIX Epoch时间的小时值(该计时方式以1970年1月1日 星期四 00:00:00作为起始时间)。在一段时间内,客户端和服务器应该在不同的本地时间用完相同的小时值。然后,会计算数据包中三个部分的HMAC值,加上字符串中的小时值。同样,其结果长度为20h字节,前10h字节作为数据包的第四部分。

Obfs4proxy.exe发送客户端的握手数据包:

5.png

上图是OllyDbg的截图,展示了客户端的握手数据包。我将截图中的内存部分分为四块,每个部分标记了不同的颜色。在这种情况下,填充数据的长度为52h字节。第三部分(“mark”)和第四部分(“HMAC of Entire Data”)可用于在服务器端验证客户端的握手数据包。

即使我们正确使用了上面的所有数据,但如果系统当前的时间不正确,Obfs4网桥的握手过程仍然会失败。下面展示了详细的情况,因为我的测试系统时间没有同步,导致服务器在数据包4中收到客户端握手后,TCP会话在数据包6关闭。

由于系统时间不正确,服务器端身份验证失败:

6.png

建立连接请求后,Obfs4中继将启动一个新线程来处理与客户端的通信,客户端也将在该线程中处理握手数据包。服务器端执行与客户端相同的操作,也就是生成与客户端密钥对相对应的服务器密钥对实例。通过调用curve25519.ScalarBaseMult(),从随机选择的私钥中计算出代表密钥和公钥。

然后,服务器端解析并验证客户端的握手数据包。在确保数据包的所有内容正确无误后,通过调用函数extra25519.RepresentativeToPublicKey()从握手数据包第一部分的代表值中恢复出客户端的公钥。

下一步,对于ECC算法的“标量乘法”(Scalar Multiplication,函数curve25519.ScalarMult())来说至关重要。标量乘法是一种单向函数,不存在对应的标量除法函数,正是因此才使得ECC算法非常强大。

这里使用服务器的私钥和客户端的公钥执行标量乘法。同样,客户端在收到服务器的握手数据包时将执行相同的操作。在该过程结束时,标量乘法的两个结果必须相同,下图展现了该算法的等式。

ECC算法公式:

7.png

上述公式是ECC算法的重要组成部分,可以确保两端值相等。左侧部分是在服务器端进行计算,右侧是在客户端计算的。

这些随机生成的公钥和私钥仅在一个TCP连接会话中有效,因此它们被称为会话公钥/私钥。它们不同于ID公钥/私钥,后者针对一个Obfs4中继来说是唯一的。

在之前的章节中,我们讨论了从网桥配置行中Base64编码的“cert”中提取的IdPublicKey和nodeID。实际上,与之对应的IdPrivateKey始终保存在Obfs4中继中。

安装并启动Obfs4中继后,将会生成一个IdPrivateKey / IdPublicKey。Obfs4将保留IdPrivateKey,然后在Obfs4客户端将要使用的网桥配置行中公开IdPublicKey。这些内容都固定在某个Obfs4中继上。与会话秘钥一样,这两个密钥都是ECC概念的私有/公开密钥。

接下来,客户端和服务器都会调用ScalarMult()两次,以生成两个常见的结果。首先让我们了解一下服务器的工作方式:

服务器使用服务器的会话私钥和客户端的会话公钥调用ScalarMult(),然后再次使用IdPrivateKey和客户端的会话公钥对其进行调用。现在,我们产生了两个函数结果。然后将它们与nodeID和一些常量字符串放在一起,以生成公开的“keySeed”和服务器的“auth”。

接下来,创建服务器的握手数据包。其中包含客户端握手数据包的所有组件,并且在代表数据和一些填充数据之间,以及不同的填充数据大小范围之间包含服务器的auth元素,如下表所示。

服务器的握手数据包结构:8.png

服务器的auth元素用于客户端的身份验证。填充数据的大小范围在0h-1F73h之间,这使得数据包大小在一个较大的范围内呈现随机化。随后,将该数据包发送回客户端(obfs4proxy.exe)进行验证。我们知道,服务器现在具有用于当前TCP连接会话的通用“keySeed”。

当服务器的握手数据包返回到客户端时,将验证数据包的最后两部分,以确保该数据包有效。然后,它从数据包的第一部分(即:server.representative)中提取服务器的会话公钥。

现在,客户端可以两次调用ScalarMult(),这一点与服务器端一致。使用客户端的会话私钥和服务器的会话公钥调用ScalarMult(),然后使用客户端的会话私钥和IdPublicKey再次对其进行调用。

同样,我们会得到两个函数结果。然后,客户端将二者进行组合,并添加与服务器相同的nodeID和一些常量字符串,以生成公共的keySeed和auth数据。然后,客户端将生成的auth数据与服务器握手数据包中的数据进行比较,从而完成验证过程。

这里生成的普通keySeed客户端应该与服务器的客户端完全相同。使用这个通用的keySeed,客户端和服务器都可以继续生成其自身的最终加密/解密密钥,用于Tor-Payload的加密和解密。客户端的加密密钥与服务器的解密密钥相同,客户端的解密密钥与服务器的加密密钥相同。

上述就是Obfs4客户端与网桥之间的完整握手过程。其结果会使数据包的大小随机化,因为具有较大的范围,并且其数据看起来也是随机的,这使得握手数据包变得更加难以识别。

Obfs4封装Tor Payload

客户端和服务器都使用从公开keySeed派生的加密密钥和解密密钥来初始化其编码器、解码器实例。然后,Obfs4使用这两个实例来实现Tor Payload的封装和解封装。编码器实例用于加密,解码器实例用于解密。

目前,obfs4客户端有两个连接,一个用于在Tor(tor.exe)与Obfs4客户端(obfs4proxy.exe)之间交换数据,另一个用于在Obfs4网桥客户端和网桥中继之间进行Tor Payload传输。握手过程完成后,Obfs4客户端将绑定两个连接。下图展现了负责绑定两个连接的函数copyLoop(位于源文件obfs4proxy.go)中的代码,其中参数“a”和“b”是两个连接的实例。

函数copyLoop的源代码:

9.png

函数“io.Copy(destination, source)”负责将数据从源复制到目标。具体过程如下:首先调用source.Read()函数,然后从中提取特定数据,然后再调用destination.Write(),并在参数中提取该数据。

Obfs4客户端将重写Write()和Read()。Write()函数加密Tor的Payload数据包(称为“封装”),并将封装的数据发送到Obfs4中继。因此,Read()函数负责从Obfs4中继接收数据包,然后将其解密(称为“解封装”)。随后,io.Copy将解密的Tor数据包传输到Tor。

重写的Write()和Read()函数:

10.png

我们来详细分析一下这两个函数是如何实现的。如上图所示,它在Write()中调用函数makePacket(),然后在其中调用另一个函数Encoder.Encode()来加密Tor Payload。然后,在函数readPackets()中调用Decoder.Decode(),该函数在Read()中调用。

Encoder.Encode()最终调用secretbox.Seal()进行加密,并生成Tor Payload的MAC。相应地,Decoder.Decode()调用secretbox.Open()解密从Obfs4中继接收的Payload。

加密后的数据不仅仅是Tor Payload,该Payload也将被复制到偏移量+3的数据缓冲区中。因为前3个字节是一种标头结构,其中包含刚刚复制的Tor Payload的包类型和大小。这也就是Encoder.Encode()加密的所有数据。

要加密的Tor Payload:

11.png

下图展示了Obfs4客户端即将调用Encoder.Encode()的示例。其包含的参数之一指向内存中的数据缓冲区,其中第一个字节是数据包类型(00表示是Payload数据包),其后的0x00BF是网络字节顺序的Tor Payload大小。从偏移量+3开始的数据是Tor Payload,来自于tor.exe。

Obfs4还通过将随机大小的填充数据附加到加密数据的方式,来混淆数据包的大小,这也是阻止审查的一种方式。

具有IAT模式的Obfs4拆分数据包

除了随机填充数据之外,Obfs4还支持另一种反检测技术,可以对抗审查,即IAT模式。

在我们之前的分析里,在描述Obfs4网桥信息时提到了IAT模式。IAT模式是“Inter-Arrival Timing”(到达间隔时间)的缩写,可以将较大的数据包(大于1448字节大小的数据包)拆分成MTU大小(最大传输单元)或更小的数据包。MTU定义为可用于传输数据的最大数据包或帧大小。网络驱动程序将大数据包拆分成MTU大小的数据包(在TCP握手过程中协商),可以轻松地对其进行重组,并可能会被检测到。因此,Obfs4引入了IAT模式。

在Obfs4中,IAT模式的值可以分为0、1或2。

其中,0表示禁用IAT模式,网络驱动程序将拆分较大的数据包,这样的特征可能会被检测到。

1表示将大数据包拆分成MTU大小的数据包,而不再让网络驱动程序执行此操作。这里,Obfs4网桥的MTU为1448字节。这意味着较小的数据包无法重组以进行分析和检测。图10展示了计算MTU大小的Obfs4代码片段。

2表示将大数据包拆分为大小可变的数据包。

Obfs4的MTU大小:

12.png

较小的拆分数据包会分别发送到Obfs4中继。这样一来,就可以混淆任意网络指纹,使Obfs4流量更加难以被识别。

下图展示了Obfs4通信的示例,其IAT模式设置为1。红色标出的是一个大数据包,按照IAT模式进行拆分。蓝色表示的数据包是拆分后得到的小数据包。对于其中的第一部分数据,原始数据包大小为2719,被拆分为两个Obfs4 MTU大小的数据包(1448)。

启用了IAT模式的Obfs4流量:

13.png

通过其他方式获取Obfs4网桥

Tor用户可以通过三种方式来获取Obfs4网桥:Tor网络设置、Tor网站以及电子邮件。每次用户可以获得3条Obfs4网桥配置行。下图展示了获取Obfs4网桥配置行的Tor网桥网站截图。

Tor网站,用于获取Obfs4网桥:

14.png

获取Obfs4网桥后,接下来需要复制粘贴这些信息以使其正常工作,如下图所示。

复制粘贴三个Obfs4网桥:

15.png

总结

经过我们对Obfs4网桥的分析,我们了解到它可以有效保护Tor流量不会被检测机制发现和阻止,其原因在于:

1、Obfs4通过添加填充数据(包括在握手数据包中添加填充数据)来加密Tor流量并混淆数据包大小特征。

2、可以通过IAT模式拆分较大的Obfs4数据包,以模糊其网络指纹。

3、除了内置的Obfs4网桥之外,Tor还提供了三种其他方式来获取私有的Obfs4网桥。


  • 分享至
取消

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

扫码支持

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

发表评论

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