如何搭建TCP代理(一)

如何搭建TCP代理的项目还是源于我的一次有趣的尝试,有天下午,我打算攻击流行约会应用程序的用户定位功能。我想看看它们是否容易受到攻击,这些攻击可以逆转受害者用户的位置。我的计划是欺骗每个目标应用程序的数千个请求,假装每个请求都是从不同的位置发送的,并且每次询问应用程序我的目标与我当前的虚假位置有多远。接下来,我会结合使用数学和独创性得出的结果来尝试找出确切的位置。

项目一开始开始进展顺利,通过使用Burp Suite(一种流行的HTTP代理),我可以检查、编辑和重播手机与各种约会应用程序的远程服务器之间发送的所有HTTP通信。但是,当我开始探索一个非常成功的应用程序时,我立即遇到了麻烦。我发现它的通信没有出现在Burp或我的其他任何其他基于HTTP的标准工具中。我花了很长时间检查并再次检查我的设置和配置。最后我发现,他们根本不用HTTP。他们使用了其他一些神秘的但仍基于TCP的协议,而我的常规工具(如Burp)无法使用。

出于好奇,我花了一些时间来构建一个通用的TCP代理,它可以处理任何基于TCP的协议,而不仅仅是HTTP。一旦完成,我的代理允许我检查不合作的应用程序与服务器的通信。这意味着,我可以继续伪造个人资料,并获得一些希望的结果。

在接下来的文章中,我将向你展示如何构建自己的TCP代理。在本文结束时,你将能够使用代理来拦截、记录、编辑和重播智能手机的所有TCP流量,而不仅仅是HTTP。在本文中,你将学到很多基础互联网的关键技术,包括DNS,TLS和TCP。

什么是代理?

所谓代理,就是代表客户将消息发送到服务器的中介。

代理广泛用于隐私浏览、内容过滤、绕过审查、缓存和安全渗透测试。

本文,我们将构建一种称为“中间人”(MITM)的特殊类型的代理。安全渗透测试人员通常使用MITM代理来读取、记录和修改客户端(如智能手机)与远程服务器(如约会应用程序)交换的数据。

假设你想使用MITM代理(在你自己的笔记本电脑上运行)来检查与你喜欢的约会应用程序之间的通信流量。你将指示智能手机将其流量发送到MITM代理,而不是直接将其发送到约会应用程序的服务器。此时,你的智能手机将不再询问约会应用程序的服务器“Alex距离多远?”。相反,它会让你的MITM代理询问约会应用程序Alex离你有多远。

你的MITM代理将发出此请求,并将收到的任何响应发送回你的智能手机。它还会将请求和响应的内容记录到文件中,使你可以查看其中包含的内容。这就是使代理成为中间人的原因。你可以使用这些日志中的信息来修改智能手机发出时的请求,甚至可以从一开始就伪造你自己的请求。

代理设计

在本文中,我们的代理将包括3个组件,每个组件负责解决一个不同的问题:

1. 一个假冒的DNS服务器,诱骗你的智能手机,将其TCP流量发送到伪造的代理;

2. 代理服务器,用于管理智能手机和远程服务器之间的数据流;

3. 伪造的证书颁发机构,用于处理智能手机和我们的代理之间的TLS加密。

本项目计划分为4部分,第一部分会概述代理设计,并介绍了我们将使用的协议和技术。最后三部分分别描述了如何构建上述组件,并为所涉及的技术做一些额外的说明。

构建伪造的DNS服务器

我们将首先构建一个伪造的DNS服务器,并使用伪造的DNS服务器诱骗你的智能手机将其流量发送到伪造的代理。

用户会考虑使用主机名(例如robertheaton.com)将数据发送到网络上。但是,互联网使用IP地址(例如104.18.33.191)将数据路由到其目的地。这两个地址系统是完全不同的,IP地址对人类来说很不方便(“访问我的网站104.18.33.191”不是很方便),但主机名对互联网主干来说绝对没有任何意义。

诸如智能手机之类的设备使用域名系统(DNS)协议在主机名和IP地址之间进行转换,大约有20台免费的和公共的DNS服务器,每台服务器(大致而言)都保留一个数据库,其中包含从主机名到IP地址的所有映射。 Google有一个IP地址为8.8.8.8的DNS服务器,Verisign有一个是64.6.64.6。

假设你浏览到网站robertheaton.com,在你的设备向我的服务器发送请求之前,它需要将此主机名转换为互联网主干可以理解的IP地址。它向DNS服务器发出DNS A记录请求(以下简称为“DNS请求”),要求其将robertheaton.com转换为IP地址。一旦DNS服务器以104.18.33.191响应,你的浏览器就会向互联网发送一个HTTP请求,地址是这个IP地址。

你可以通过在智能手机的系统设置中输入服务器的IP地址,来选择智能手机用于进行这些DNS转换的DNS服务器。所有主要的DNS服务器都应给出相同的正确答案,因此通常这种选择实际上并没有多大意义。

什么是虚假DNS服务器?

DNS服务器没有什么特别的,它只是一台监听并响应UDP端口53上的DNS请求的服务器。实际上,我们可以在笔记本电脑上运行我们自己的DNS服务器,并且可以将你的智能手机配置为使用此虚假DNS服务器,而不是Google或Verizon的DNS服务器。

这样,我们就可以对虚假DNS服务器进行编程,以发送回我们喜欢的任何DNS响应。我们甚至可以让它返回的消息全部都是虚假的。假设我们的DNS服务器收到了一个主机名的DNS请求,我们希望通过我们的代理(例如api.targetapp.com)路由该主机名的请求。我们将对服务器进行编程,使其不响应api.targetapp.com的真实IP地址,而是响应你笔记本电脑的本地IP地址。

你的智能手机不会知道我们响应了虚假信息,也不会看到这些回复有任何问题。它将接受api.targetapp.com解析为笔记本电脑的本地IP地址,并将它希望发送到api.targetapp.com的任何数据发送到你的笔记本电脑。

要利用此行为并接收重新路由的数据,我们将需要在笔记本电脑上设置第二台服务器。这将是实际的代理服务器,它将负责从你的手机接收数据,阅读并打印数据,以便我们进行检查;最后将其转发给预定的收件人。

为什么我们不能只进行Burp操作?

实际上,像Burp这样的HTTP/S代理不需要做任何DNS欺骗来让你的智能手机向他们发送数据,但为什么我们还要进行TCP代理?

因为,像Burp这样的HTTP/S代理使我们广泛使用了HTTP协议的一些高级功能,这些功能的存在只是为了帮助代理,其中包括连接请求和HTTP 主机标头,稍后我会详细介绍。

现在所有的智能手机都利用了这些功能,因此可以很好地与HTTP/S代理一起工作。你的智能手机有一个系统设置,允许你指定一个代理,它应该使用所有的HTTP请求。为了使用像Burp这样的HTTP MITM代理,你首先要将笔记本电脑和智能手机连接到同一网络,然后告诉你的智能手机将笔记本电脑的本地IP地址用作HTTP代理。你在笔记本电脑上打开Burp代理,智能手机就会乖乖地把所有的HTTP/S流量转发到笔记本电脑上。此时,Burp立即启动并运行。

但是,由于我们希望代理能够处理所有基于TCP的协议,而不仅仅是HTTP,因此我们无法利用任何特定于HTTP的功能,这就是为什么我们不得不求助于我们的DNS hijinks的原因。你遇到的其他基于TCP的协议可能具有其等效的代理友好功能,但同样也可能没有。此时你将无法知道正在检查的特定协议是否具有任何此类功能,直到你能够使用代理检查其请求,并且在检查了其请求之前,你将不知道如何代理其请求。

现在,我们知道了如何诱骗智能手机将TCP数据发送到笔记本电脑,现在,让我们看看如何使用它来做些事情。

代理服务器

现在要讲的是代理服务器本身,本文要讲的是一台在笔记本电脑上运行的服务器。它会接受来自你的智能手机的流量(但前提是在我们伪造的DNS服务器的帮助下),将其转发到目标应用的远程服务器,并将它得到的任何响应发送回你的智能手机。

本文,我们将要解决的主要问题是确保我们的代理知道将智能手机流量转发到哪个远程服务器。像所有计算机程序一样,代理程序并不是很聪明。它们不知道如何处理收到的数据,而唯一知道这些数据的方法是明确地告诉他们。

比如,当你想和朋友共进晚餐时,你会给他们的手机号码发短信,说“今晚想去吃晚餐吗?”

现在,假设你有一位私人助理,你将雇用该助理来转发所有文本。过程如下:首先你将所有文本发送给该助理,然后它们代表你转发给你的朋友。如果你仅向该助理发送短信,说“今天晚上想吃晚饭吗?”他们是不知道将其转发给谁。有很多方法可以解决以上出现的代理问题。比如,你可以在消息后面附加一个标题“Send-To: 415-123-1234”,或者你可以提前制定一个规则,将所有晚餐建议始终发送给你的母亲。

同样,HTTP/S代理可以使用HTTP协议的特殊、特定于代理的特性轻松地解决这个路由挑战。不过,我们不能使用它们,因为我们希望我们的TCP代理完全与应用程序协议无关。

因此,我们要稍微作弊一下。我们将把一个主机名硬编码到我们的代理中,并告诉我们的代理将它接收到的所有数据转发给这个主机。这就好比告诉你的私人助理,把你今天发送的所有消息信都转发给你的一个好友或信任的人。

以上只是我的一个简单比喻,通常,你将使用代理检查每个应用发送的数据。此应用可能会将其所有有趣的数据发送到一个主机名,例如api.targetapp.com。

我们可以查看前一节中的虚假DNS服务器的日志,并查看你的智能手机尝试联系的主机列表。我们可以使用直觉和猜测来找出最有趣的主机名。例如,api.targetapp.com可能比stats.mobileanalytics.com更有趣。然后,我们可以将该主机名硬编码到我们的代理中,并指示我们的代理将它从你的智能手机接收到的所有数据发送到这个主机。

请注意,我们将需要配置伪造的DNS服务器,使其仅发送与代理程序将所有数据发送到的主机名相同的代理流量。对于所有其他主机名,我们的虚假DNS服务器应向真实DNS服务器发出真实DNS请求,并将此真实响应转发到你的智能手机。这将导致你的智能手机绕过我们的代理,将这些主机名的所有流量直接发送到正确的位置。如果我们不这样做,我们的代理最终可能会将敏感数据转发到错误的服务器。

 Burp如何路由请求?

我提到过,Burp和其他HTTP/S代理使用HTTP协议的特殊功能来路由请求。为了让我们知道我们遗漏了什么,让我们看一下这些特殊功能,以及它们如何帮助代理同时路由HTTP和HTTPS流量。

HTTP代理

未加密的HTTP代理很容易做到,HTTP/1.x 请求包含一个主机标头,该标头明确指定了请求应发送到的主机名。 HTTP/2.x 请求包含一个包含相同信息的授权伪标头。 HTTP代理可以轻松地从未加密的请求中解析出该值,然后相应地重新发送该请求。这类似于在发送给助手的短信中包含“发送至”字段。

 HTTPS

HTTPS代理更难,目前HTTPS代理有两种主要类型:转发代理和中间人代理。 “转发代理”非常无聊,它代理HTTPS数据,而无需解密。但是,它无法重用HTTP代理所采用的方法,因为它只会将通过它的数据视为不可读的、TLS加密的废话。这意味着它无法读取HTTP 主机标头,因此无法使用它来重定向通过它的数据。因此,它需要一个替代解决方案。如果你的私人助理不能解密你的朋友的名字,那么即便把你的朋友的名字发给你的私人助理是没有用的。

HTTPS协议通过向代理发送额外的特定于代理的连接请求来解决此问题,如果客户端知道其HTTPS请求将通过代理传递,则它在每个客户端之前都有一个单独的HTTP 连接请求。该请求以未加密的明文形式明确地告诉代理服务器,它应该向其发送稍后将发送的加密请求的主机名。这意味着代理无需解密主有效载荷即可正确路由。这就像给你的私人助理发送一条事先没有加密的文本信息,内容都是一些教助理应该如何处理即将发送的加密信息的废话。

第二种类型的HTTPS代理,也是我们本文讲解的要构建的类型,是“中间人”(MITM) 类型。正如我们已经讨论过的,MITM不同于转发代理,因为它能够解密和读取通过它的数据。这意味着它可以读取HTTP请求的明文内容,因此也可以读取存储在其HTTP主机标头中的目标。HTTPS MITM可以将请求转发到此位置,其方式与HTTP代理完全相同。

MITM通常仍然倾向于模拟转发代理,并在可能的地方使用连接请求。他们唯一使用主机标头的时间是在“不支持代理”的客户端不知道或不在乎他们是否连接到代理,并且不发送初步的连接请求时。在这种情况下,主机标头是一个有用的后备。

现在,我们知道了如何说服你的智能手机将其数据发送给伪造的代理,以及如何确保伪造的代理安全地接收这些数据。接下来要做的就是如何处理你的智能手机和虚假的代理之间的TLS加密。

 伪造证书颁发机构

希望你尝试检查的基于TCP的协议使用TLS加密,在2018年,互联网仍然是一个非常危险的地方,没有任何理由不对所有内容进行绝对加密。

TLS(有时称为SSL)是HTTPS用来保护你的网上银行详细信息安全的一种加密形式。但是,TLS可以用于任何基于TCP的协议,而不仅仅是HTTPS。这是因为TLS不在乎它加密的数据形式。它可以是HTTP、FTP、XML或完全是非结构化的,这意味着我们的TCP代理可以重用HTTPS代理通常记录和使用的所有相同TLS技术。

我们需要解决的主要TLS问题是,说服你的智能手机信任我们的代理。完成此操作后,解密智能手机发送的数据的任务将非常简单,因为我们可以将其委派给已知的,经过良好测试的库。

 TLS证书和证书颁发机构

常情况下,你的智能手机对外界持怀疑和不信任的态度,知道声称代表api.targetapp.com的服务器真正属于谁,这意味着什么?如果智能手机将数据发送给错误的人,那么你就没有必要仔细地保护和加密你的数据。

TLS加密可缓解智能手机的偏执狂,同时使我们的工作更加困难。 TLS不仅在发送数据之前对其进行了加密,它还会验证它是否将加密的数据发送到正确的位置。

TLS连接通过称为TLS握手的过程进行同意和验证,在TLS握手期间,客户端和服务器将彼此介绍自己。客户端验证服务器的身份(有时反之亦然),并且双方同意使用加密密钥来保护其流量。这意味着,他们通过TCP连接交换所有这些信息。

你的智能手机将不会完成与我们的代理的TLS握手,除非我们能够通过出示有效的TLS证书来证明我们的代理的身份。为此,我们需要将这个TLS证书的公共名称(证书中的一个字段)设置为你的智能手机认为正在与之通信的主机名,这将很容易。另外,我们还需要使用智能手机信任的根证书颁发机构(CA)对TLS证书进行签名,这个过程将是困难的。

主机名(如google.com)的真实TLS证书(由Digicert等真实的CA签署)将是世界历史上最有价值的几千个字节之一,因为它会允许恶意攻击者解密由任何人都可以访问google.com。如果你拥有此类证书,请立即停止阅读。

由于我们没有任何真实的,由CA签名的TLS证书,因此我们将制作自己的虚假CA,我们将之称为“罗伯特的信任证书颁发机构(Robert s trusted Certificate Authority)”。我们将为我们的CA生成一个签名证书,并将此证书作为根CA安装在你的智能手机上。这将使你的智能手机信任我们的CA,更重要的是,信任我们的CA签署的所有其他证书。每当你的智能手机要求我们的代理执行TLS握手时,我们都会检查你的智能手机认为与之对话的主机名。我们将快速为该主机名生成一个证书(例如api.targapp.com),并用我们的伪造CA对其进行签名,最后将其返回给你的智能手机。此时你的智能手机将看到api.targapp.com的此证书已由“罗伯特的信任证书颁发机构”签名,看到此信誉良好的组织位于其受信任的CA列表中,并很高兴与我们的代理完成TLS握手。

随着你的智能手机和我们的代理之间的TLS连接成功构建,我们的系统的其余部分将完全按照计划工作。此时,TCP代理就已经完成。

 TCP代理的详细过程

该过程分为3个步骤:

1. 伪造的DNS服务器,在笔记本电脑上运行的DNS服务器,欺骗你的智能手机将其TCP流量发送到笔记本电脑

2. 代理服务器,在笔记本电脑上运行的服务器,可以处理智能手机和远程服务器之间的流量;

3. 伪造的证书颁发机构,一种生成智能手机将信任的TLS证书的工具。

完成以上3个步骤后,你将拥有一个可以正常工作的TCP代理,可用于检查和分析任何基于TCP的协议。我已经使用Python3为每个部分编写了示例代码。虽然这也意味着你最好使用Python3,但是用另一种语言实现TCP代理也是完全可行的。

 伪造DNS服务器

伪造DNS服务器的代理将能够处理任何基于TCP的协议,而不仅仅是HTTP。

接下来,我们将构建一个在笔记本电脑上运行的虚假DNS服务器。我们将配置你的智能手机,使其在需要使用DNS将主机名解析为IP地址时使用该服务器。当你的智能手机向我们的服务器询问目标应用程序的主机名的IP地址(例如api.targetapp.com)时,我们的服务器将处于说谎状态。它会返回你笔记本电脑的本地IP地址,而不是返回目标应用程序的真实IP地址。

此时,你的智能手机将信任我们服务器的响应,并误认为你的笔记本电脑的本地IP实际上是api.targetapp.com的正确IP地址。现在,只要你的智能手机希望向api.targetapp.com发送一些数据,它就会将其发送到你的笔记本电脑,而不是真正的TargetApp服务器。这将完成你的智能手机数据必须通过我们的代理系统进行的第一跳。在接下来,我们将构建一个代理服务器,以监听并利用此重新路由的数据。

 深入了解DNS

在开始使用我们的虚拟DNS服务器之前,我们将使用一些现有的工具来详细研究一些真实的DNS请求。我们还将手工制作和欺骗一些DNS响应,证明你的手机确实会信任并响应包含笔记本电脑发送的虚假的DNS响应。尽管我们的代理经过明确设计,能够处理非HTTP TCP流量,但我们将首先使用HTTP请求对其进行测试,不过,这纯粹是为了简单起见。通常,让智能手机发出HTTP请求要比其他任何类型的TCP请求都容易,因为触发一个网站所需要做的就是访问网站。不过我们的代理不是“non-HTTP”,而是“non-HTTP-specific”。

如果你尚未下载,请下载Wireshark和netcat(nmap的一部分)。Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Netcat被称为网络安全界的瑞士军刀,netcat可以用于监控/扫描网络端口,它应用最多的情况是后门程序。

 将智能手机的DNS请求发送到笔记本电脑

首先,让你的智能手机将DNS请求发送到你的笔记本电脑,而不是将当前配置为使用的任何真实DNS服务器(例如Verisign,Google或OpenDNS)发送给你。

首先,请确保你的笔记本电脑和智能手机连接到同一无线网络。

接下来,通过运行一个类似 ifconfig | grep en0 -A 2 | grep netmask的终端命令来查找你的笔记本电脑的本地IP地址,如果你使用的是Windows系统,请尝试ipconfig。该命令应将笔记本电脑的本地IP地址打印到终端上,这可能看起来像192.168.x.y。

现在找到你的智能手机的DNS设置页面,此时你可以更改你的智能手机向其发送DNS请求的DNS服务器。将DNS服务器IP地址更新为你刚刚发现的笔记本电脑的本地IP地址,尝试访问一些网站并使用一些应用程序,但最终你会发现这些网站和程序都无法工作。

此时,你的智能手机已停止运行,因为它已开始将其所有DNS请求发送到你的笔记本电脑。由于你的笔记本电脑不知道如何处理这些请求,所以它会将它们丢弃而不产生响应。这意味着你的智能手机无法将主机名解析为IP地址。尽管它在技术上仍可以连接到互联网,但我们已经打破了它的一个主要机制来解决如何使用它。互联网上的路由是使用IP地址而不是主机名完成的。互联网主干网不知道怎么去targetapp.com,就像你的出租车司机不知道怎么去你的约会对象的家一样。

  探测DNS请求   

使用Wireshark探测DNS请求

我们已经成功断开了你的手机与网络的连接,我觉得这是个好消息,因为它表明你的手机已开始向笔记本电脑发送DNS请求。现在,让我们使用数据包嗅探器Wireshark来检查你的笔记本电脑的网络流量,并查找你的手机命中注定的DNS请求,看看我的判断是否正确。我们可以确认它们确实被发送到你的笔记本电脑,并且你的笔记本电脑目前没有向你的手机发送任何DNS响应。

在诱骗你的智能手机之前,让我们先进行一次基本检查以确保Wireshark正常运行。首先,在笔记本电脑上打开Wireshark,并使用udp端口53来运行它。DNS请求通过端口53上的UDP协议发送,这将屏蔽掉我们不感兴趣的网络流量。现在,在笔记本电脑上,可以访问任何网站。你应该在Wireshark中看到该网站的主机名的DNS请求和响应,这是你的笔记本电脑向真正的DNS服务器发出自己的DNS请求,以便它可以将浏览器(例如robertheaton.com)的HTTP请求从你的浏览器发送到正确的IP地址。

DNS请求

DNS响应

如果这不起作用,那么也可以尝试其他一些网站。你的笔记本电脑可能最近向robertheaton.com发出了DNS请求,并且可能已缓存收到的响应。

现在,让我们查看手机中的一些DNS请求。首先,让我们调整Wireshark过滤器。 udp端口53过滤器同时显示发送到笔记本电脑和由笔记本电脑发送的DNS请求。。通过处理,我们只显示通过你的手机发送到你的笔记本电脑的请求。将Wireshark过滤器更新为udp端口53 && dst $ YOUR_LAPTOPS_IP。在你的智能手机(其DNS服务器仍设置在笔记本电脑上)上,访问另一个网站。不过,由于DNS缓存,你可能不得不多尝试几次。你应该在Wireshark中看到针对此网站主机名的DNS请求,并将其UDP数据包的“目标IP”字段设置为你的笔记本电脑。如果你这样做,则可以确认你的手机正在与笔记本电脑通话,这是一个巨大的诱骗方法的突破!

但是,Wireshark不会显示相应的DNS响应。这是因为我们尚未告知你的笔记本电脑,当它在端口53上收到UDP数据包时,会发生什么?

在开始对笔记本电脑进行设置之前,让我们使用Netcat从另一个角度来看一下DNS流量。(未完待续)

参考及来源:

https://robertheaton.com/2018/08/31/how-to-build-a-tcp-proxy-1/

https://robertheaton.com/2018/08/31/how-to-build-a-tcp-proxy-2/

https://robertheaton.com/2018/08/31/how-to-build-a-tcp-proxy-3/