上一篇文章翻译完了 RFC 1928 ,但是感觉仅仅只看协议标准文档的话会有点不够具体,所以抓包分析了一波 SOCKS 5 协议的具体交互流程,这里记录一下分析过程。前期的软件准备相信来看文章的人都知道如何去准备,这里不再赘述,直接步入正题。本文可能要对照标准文档阅读,传送门: RFC 1928 - SOCKS 5 协议中文文档「译」

交互第一步操作

根据标准文档,所有的操作第一步显然是建立 TCP 连接,然后进行指令交互。整个流程抓包如下图 (点击想看的图片细节位置即可放大对应位置),最左侧为数据包序号:

数据包抓包截图 - 整体流程

首先看前三个数据包,很典型的 TCP 握手连接,服务端为本地 1080 端口,源端口为本地 48398 端口,建立连接完毕之后,第 4 个数据包 Wireshark 已经自动识别了其为 SOCKS 数据包,查看其详情:

SOCKS 协商认证方式数据包 - 抓包截图

与文档一致,版本号 X‘05’ ,可选方法数目 X‘01’ (一种),方法列表此时显然只有一个字节,其值也对应为 X‘00’ 。根据文档显然其对应为 SOCKS 5 版本,客户端只有一种协商方法 —— 无需认证。其实仔细看上图, Wireshark 这些信息都有对应翻译成英文。紧随其后的第 5 个数据包为 TCP 的 ACK 包,跳过,第 6 个数据包如下:

SOCKS 协商认证方式回复数据包 - 抓包截图

这一步也与文档一致,为协商认证方式的回复数据包,版本号 X‘05’ ,选择的认证方式为 X‘00’ 。可见无需认证,后续直接进行指令交互就可以了。同样的 Wireshark 也已经对应翻译了。

TCP 请求流程

第 7 个数据包为应用发送到 SOCKS 服务端的 TCP ACK 包,第 8 个数据包正如协议描述,为指令请求,抓包样例为 CONNECT 指令,具体如下图:

SOCKS 5 TCP CONNECT 指令请求报文

只需要注意一下新碰到的字段: CMD 字段为 X‘01’ 表示 CONNECT 指令,保留字段确实为 X‘00’ ,地址类型为 X‘03’ 也就是域名,域名开头为 X‘0d’ 也就是十三,数一数 www.googoe.cm 确实长度为 13 ,是的,测试的时候把 com 打错成了 cm ,不过该域名也是合法的。所有内容 Wireshark 依旧有翻译。

第 9 个数据包为第八个数据包的 TCP ACK 数据包,同时稍带了数据,也就是 SOCKS CONNECT 指令的应答报文,报文详情如下:

SOCKS 5 TCP CONNECT 指令请求 - 应答报文

报文内容 REP 字段为 X‘00’ ,表示指令执行成功,其他各个字段前面基本都有遇到了,但是需要注意一下其返回的地址与端口。按照标准文档,其应当为 SOCKS 5 服务连接目标服务采用的地址和端口,其中端口为 4112 倒没什么,为什么 IP 地址为 0.0.0.0 呢?首先需要确认一点,事实上,这个对应的真实地址,应用软件的客户端是用不到的,所以事实上是返回什么都没关系。这个样例里面返回为 0.0.0.0 是因为测试抓包的时候,我所使用的提供 SOCKS 5 服务的软件的自身原因(我测试过多台机器,也尝试更改过该软件的各项配置,发现最终返回的地址和端口都是固定的)。

在应用软件收到第 9 个数据包(且标记为执行成功)后,就可以直接开始数据发送了,所以可以看到第 10 个数据包已经是 TLS 握手包了,这里不再展开描述。

UDP 请求流程

与 TCP 类似, UDP 连接也需要上述第一步 —— “交互第一步操作”。待认证完毕,即可以开始 UDP 中继操作。提到 UDP 最先想到的应用便是 DNS 服务协议。所以博主最开始也是想着强行劫持本地 DNS 流量来进行抓包操作,但是遇到了问题, TCP 测试流量简单配置 proxychains 就可以做到了,但 proxychains 不支持 UDP 流量自动转换走对应的代理协议,没办法只能自己写一个认证流程附带发个 UDP 的包,显然没有时间完整模拟 DNS ,所以下面分析的其实只是简单通过 UDP 协议发送字符串 “mierhuo” 到 8.8.8.8 的 53 端口。

这里从 UDP 中继指令开始,数据包如下:

UDP 中继指令数据包

可以看到其 CMD 字段为 X‘03’ , 即 UDP ASSOCIATE 指令,执行UDP关联操作,需要中继 UDP 数据包到 8.8.8.8 地址的 53 端口, SOCKS 5 服务端收到该信息后,应答报文如下:

UDP 中继指令 - 应答数据包

可见 SOCKS 服务端建立关联完毕,根据标准文档可见,中继服务的地址为 127.0.0.1 ,中继服务端口为 9050 ,那么客户端直接把 UDP 数据包按照文档要求添加相应包头后,即可直接发送到这个目标进行中继,如下:

UDP 中继数据包样例

前面部分 10 个字节为 UDP 包头,包含了中继信息(与前面关联信息一致),后面从 X‘6d’ 开始为具体数据,转换为 ASCII 码即为 “mierhuo” 。可见前面的部分基本符合实验预期。那么 SOCKS 5 服务端收到该信息后会有什么动作呢?我所使用的服务和标准文档说的一样,是个“多机系统”,显然可以猜测,其会通过“内部数据沟通方式”,会发送到“出口端”机器,如下:

SOCKS 5 服务端中继 UDP 操作

显然在其“内部数据沟通方式”中,其数据经过了加密,这部分不属于 SOCKS 5 标准,具体提供 SOCKS 5 服务的应用可自行根据情况去实现。

至此,标准文档的整个流程基本分析完毕。