socks5 結合抓包詳解
圖片拍攝於 2023 年 04 月 28 日 日本奈良
SOCKS5(Socket Secure 5)是一種網絡協議,用於在客戶端和代理服務器之間進行通信。它是 SOCKS 協議的第五個版本,SOCKS5 協議支持 TCP 和 UDP 協議,並提供了認證和加密的功能。
SOCKS5 協議廣泛用於代理服務器、xx 上網、匿名訪問、負載均衡等場景。它提供了一種通用的、靈活的代理解決方案,可以在各種網絡環境和應用中使用。
RFC 1928[1] 是關於 SOCKS5 的協議文檔。
協議解析
不想看這部分可以直接跳到下面的抓包分析。
SOCKS5 工作在應用層和傳輸層之間,首先客戶端需要和代理服務器進行 tcp 連接。
連接完成後,客戶端和代理服務器之間進行協商確定認證方式。
具體就是客戶端發送認證方法請求,
-
VER 字段佔 1 個字節,表示 SOCKS 協議的版本號,目前爲 5(即 SOCKS5)。
-
NMETHODS 字段佔 1 個字節,表示客戶端支持的認證方法數量。
-
METHODS 字段佔 N 個字節,表示客戶端支持的認證方法列表。每個字節代表一種認證方法,取值範圍爲 1 到 255,對應不同的認證方式。
代理服務器在收到客戶端消息,從客戶端提供的 METHODS 字段中選擇一種支持的認證方法,並將該方法的標識填充到 METHOD 字段中。代理服務器通過這個應答消息告知客戶端選擇的認證方法。
目前的 METHOD 包含以下幾個值:
-
X'00':NO AUTHENTICATION REQUIRED。表示客戶端無需進行任何認證,可以直接進行連接或操作。
-
X'01':GSSAPI。表示使用 GSSAPI(Generic Security Services Application Program Interface)進行認證。
-
X'02':USERNAME/PASSWORD。表示客戶端需要使用用戶名和密碼進行認證。
-
X'03'到 X'7F':由 IANA(Internet Assigned Numbers Authority)分配的認證方法。這些方法可能具有特定的定義和用途,可以根據具體的分配情況來確定其含義。
-
X'80'到 X'FE':保留給私有方法(RESERVED FOR PRIVATE METHODS)。這些方法可能由特定實現或組織自定義,不在通用的認證方法範圍內。
-
X'FF':無可接受的方法(NO ACCEPTABLE METHODS)。表示代理服務器無法接受客戶端提供的任何認證方法,無法進行連接或操作。
如果返回的方法是 X 'FF',意味着失敗了,那麼客戶端需要關閉連接。
一旦協商完畢,客戶端會發送請求的詳細信息,主要包括實際要請求的目的地址和端口號。
其中各字段含義如下:
-
VER:協議版本,固定爲 X'05'。
-
CMD:連接命令,指定客戶端的操作類型。常見的取值有:
-
X'01':CONNECT。
-
X'02':BIND。
-
X'03':UDP。
-
RSV:保留字段,固定爲 X'00'。
-
ATYP:目標地址類型,指定 DST.ADDR 字段的類型。常見的取值有:
-
X'01':IPv4 地址。
-
X'03':域名。
-
X'04':IPv6 地址。
-
DST.ADDR:目標地址,根據 ATYP 字段的類型來確定具體的格式。
-
DST.PORT:目標端口,表示客戶端要連接的目標服務器的端口號。
代理服務器收到請求後,會發起到 DST.ADDR:PORT 的連接,並響應客戶端結果,
其中的值有:
REP:
-
X'00' 成功
-
X'01' SOCKS 服務器故障
-
X'02' 連接不符合規則
-
X'03' 網絡不可達
-
X'04' 主機不可達
-
X'05' 連接被拒絕
-
X'06' TTL 過期
-
X'07' 命令不支持
-
X'08' 地址類型不支持
-
X'09' to X'FF' 未分配
RSV:預留位,必須設置成 X'00'。
BND.ADDR: 服務器綁定的地址
BND.PORT: 服務器綁定的端口(網絡字節序)
當連接建立後,客戶端就可以和正常一樣訪問目標地址 "通信" 了。
此時通信的數據除了目的地址是發往代理服務器以外,所有內容都是和普通連接一樣。對代理服務器而言,後面所有收到的來自客戶端的數據都會原樣轉發到目標服務。
抓個包看看
實驗涉及到的兩個庫:go-shadowsocks2[2] 和 proxychains[3]
假設我現在有兩臺服務器,服務器 A(上海) 和服務器 B(倫敦), 服務器 B 上部署了 Shadowsocks 服務,Shadowsocks 是一個安全的 socks5 代理。
我想把機器 A 對外請求的流量都通過 B 來代理,並且指定只有發送到 A 機器的 1080 端口流量才能被代理。
通過 go-shadowsocks2 啓動程序,
參數說明,
-c: 設置 Shadowsocks2 客戶端連接到 B 機器 Shadowsocks 的配置。
-socks: 指定 Shadowsocks2 客戶端在本地監聽的 SOCKS5 代理服務器的地址。在這個例子中,客戶端在 1080 端口上監聽代理請求。
myip.ipip.net 是一個用來查詢本機公網 ip 的服務。假設我們直接在服務器 A 上 curl myip.ipip.net,那麼請求的結果,
現在我們要通過上面描述的達到輸出的是 B 服務器倫敦的 ip 地址。
我們使用了工具 proxychains,配置 proxychains,
執行之前,我們先開啓 tcpdump,我們只抓本地 1080 端口的流量,畢竟它是作爲本地其他客戶端 socks5 代理服務器。
然後執行,
最終獲取抓到的包。
前三個包是 tcp 的三次握手,這裏就不說了。
包 4 也就是客戶端發送協商認證方法請求給代理服務器,其中包含支持的認證方法列表,這裏只支持 1 種方法: 0。也就是客戶端無需進行任何認證,可以直接進行連接或操作。
包 6 服務端響應,
此時協商完畢。
包 8 是客戶端發起請求的詳細信息,裏面包含了要訪問的目標地址和端口。這裏的 address type=3 表示域名類型。
包 9 爲服務端響應:
可以看到 RSV 的值表示成功。
這裏要注意的是包 8 中的 CMD 參數。上面說到有三個值。
當客戶端發往代理服務器的數據包的 CMD 字段的值爲 0x01 時, 代表 CONNECT, 此時 DST.ADDR 和 DST.PORT 表示客戶端所想要訪問的目標主機的地址和端口, 代理服務器在收到該請求後建立代理服務器到目標主機的 TCP 連接, 並將代理服務器分配的 IP 地址和端口在返回的數據包中的 BIND.ADDR 和 BIND.PORT 表示。
其他 CMD 值含義自行查看 rfc。
但是包 9 中在對 CONNECT 請求回覆中,BIND.PORT 和 BIND.ADDR 都不是預期的值。看了 shadowsocks2 裏面的代碼,
它是直接把 ATYP 設置成 1,BND.ADDR 和 BND.PORT 設置爲 0。
因爲此時的本地 socks5 並不是最終的代理服務器,實際請求目標地址的是我們在啓動 shadowsocks2 配置的 B 機器上的 ss 服務。本身 BND.ADDR 和 BND.PORT 字段是可選的,如果服務器不提供這些信息,客戶端可以根據實際情況進行處理。
當響應成功,客戶端開始請求傳輸數據了,也就是包 10,發送了一個 http 請求。包 12 是對請求的響應。
所以實際的流轉是,
在 Shadowsocks2 中,主要通過這個函數來實現雙向數據傳輸:
也就是,
主要靠的是標準庫的 io.Copy。
最後 13-16 包就是 tcp 的 4 次揮手了。
上圖這組包還有一個很基礎的 tcp 知識點,
首先你圖上看到的 seq 都是從 0 開始的,那是因爲 wireshark 有個可以開啓 Relative Sequence Numbers 的選項。
上面的包 4 截圖可以看到包信息: Seq =1,Len=3。再看包 5,是對包 4 的 Ack, 包 6 包 7 同理。
但是你再看包 8:Seq:4,Len=20。
你在包 9 看到的也是一個 Socks 協議的包,並沒有看到專門對包 8 的 Ack。
在 TCP 通信中,並不一定每個請求都會立即收到相應的 ACK 確認包。TCP 使用了一種稱爲 "累積確認"(Cumulative Acknowledgment)的機制。ACK 確認包可能會延遲發送,或者包含在接收方發送的其他數據包中,這是 TCP 協議的一種優化機制,可以減少網絡中的包數量和傳輸開銷。
那麼我們就知道對包 8 的確認,其實是隨着包 9 的數據一起發送了。Ack=Seq(4)+Len(20)=24
完結。
[1]https://www.rfc-editor.org/rfc/rfc1928
[2]https://github.com/shadowsocks/go-shadowsocks2
[3]https://github.com/haad/proxychains
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/5n7_x52VHY2U0EX6DIEvig