【翻牆慢報】俺的 WireGuard 被牆了!

【翻牆慢報】俺的 WireGuard 被牆了!

俺用 WG 保護 D4DJ 不被踢下線,
但是今天早上 GFW 橄欖了俺的 WG!

然後俺把監聽端口切到了 443,於是又被牆了。

SE 自稱是最快 VPN,WG 也這麼說

群裏的消息精通人士在 2020 年 3 🈷️️就聞到了 Wireguard 的風氣,然後一瞬吹爆,土老冒的俺直到三個月之後才肯嘗試用牠一下。在此之前俺最喜歡用的 VPN 是 Softether,因爲牠功能全,設定起來簡單,特別適合像俺這樣的電腦中級高手。

softether 用最簡單的配置實現最靈活的組網方案,深刻體現了日本人細緻入微的設計美學

——電腦中級高手

Softether 能拿來組網,翻牆,但是並不意味着牠適合幹一切事情。在俺的印象裏面,SE 是一個笨重的玩意(Windows 上要 40 多 MB,甚至兼容 Win 98),三十多萬行代碼裏面縫合了十萬甚至是九萬個功能,甚至支持了 OpenVPN 協議,而且牠傳輸的是二層乙太網幀,模擬的是乙太網交換 HUB。在普通翻牆的時候先開個虛擬網卡,然後 TLS 握個手,協商一下加密和 UDP 加速(實際上是減速),然後再來幾個廣播整點 DHCP 分配個 IP,之後才能上網,這麼大的開銷有點像是核彈炸蚊子,因此不適合在手機上使用(官方也沒有手機版)。

不過就算這麼笨重的 SE 都宣稱自己性能屌打 OpenVPN,實際上性能還過得去(不開加密一切都好說,哈哈)。

圖 1 世界最快 VPN,麻了![ 1 ]

剛出世的 WG 宣稱自己代碼精簡(只有 4000 行,簡直是藝術精品!),協議簡單(UDP 實現),不用的時候不跑流量(相比 SE 分分鍾就有 114 甚至是 514 個廣播乙太網幀,所以 SE 簡直就是羅嗦大媽),還使用最先進加密方法,CPU 跑起來不費勁 [ 2 ],所以 WG 特別適合用在手機或者垃圾路由器上。

圖 2 SE 大量廣播

WG 是三層 VPN,能傳輸 IP 報文。但是 4000 行的藝術精品相伴而來的就是某些實用功能的消失,SE 支持的 DDNS,多個監聽端口和 hub,無腦的 GUI 介面設定 WG 上都沒有,在某些系統上 OSPF 路由也不能穿過 WG(軟件 bug?)。SE 甚至還能號稱自己的 TLS 實現如果想要牆掉,防火牆管理員就只能老老實實地設定白名單!

圖 3 只有白名單才能橄欖我![ 3 ]

圖 4 SE 的手繪廣告

WG 當然沒有這種底氣,因爲 WG 能輕易被 Wireshark 甚至是 iptables 識別出來,還沒輪到 GFW 上場,,,

iptables -A FORWARD -p udp -m length –length 120 -m u32 –u32 “0 >> 22 & 0x3c @ 8 = 0x2000000” -j DROP

這裏的哥們說能用 iptables 牆掉 WG,俺還沒試過 [ 4 ]

你甚至可以肉眼識別 WG:

圖 5 看出來這是 WG 了嗎

消息人士表示,本版本 GFW 升級的時候 WG 還不存在,因此在 GFW 將過濾規則刻進了 ASIC 硬體加速之後才出現的 WG 對於 GFW 來說,並沒有那麼高的過濾效率。但是另一方面由於 GFW 使用了機器學習來識別流量,就連弱智都能識別出的 WG 流量說不定能被軟體實現版本的 GFW 輕鬆拿下,然後一瞬拉嗨。

而俺還妄想將 WG 端口調到 443 來逃避 GFW 的魔爪,,,

參考文獻
[ 1 ] Softether Project, Ultimate Powerful VPN Connectivity, 📎️Link
[ 2 ] WireGuard, WireGuard: fast, modern, secure VPN tunnel
[ 3 ] SoftEtherVPN GitHub, WARNING.TXT, 📎️Link
[ 4 ] StarBrilliant, Let’s talk about obfuscation again, https://lists.zx2c4.com/pipermail/wireguard/2018-September/003289.html

Shadowsocks 遭遇的困境

在 2019 年就有一位來自大數字的安全專家發現了 SS 協議裏面的缺陷 [ 5 ],由於 SS 的流加密方法沒有對數據進行完整性檢查(就像寫信沒有簽名),因此嗨客就可以通過魔改密文的方式來篡改 SS 數據中的目的地址字段,然後將這個魔改的包發回 SS 伺服器之後,傻乎乎的伺服器就會乖乖地將解密完的數據雙手奉上給嗨客(沒有簽名,伺服器不知道裏面內容被篡改了)。

嗨客通過一種聽起來有點牠馬扯的方法來用異或去碰撞 HTTP/1. 這七個字節來達到篡改目的地址和端口字段的效果,因爲 SS 翻牆通道裏面傳輸的數據很有可能經過了 HTTPS 的再次加密,所以這種方法有一點碰運氣。但是安全漏洞被發現了就有被利用的可能,所以 360 電腦高手建議大家都使用 SS 的 AEAD 加密方法。

然而 SS 的最大優點就是快,使用的簡單協議破爛 CPU 也能歡快地跑,在路由器上 SS 更是能做到比 V2Ray 快數倍的速度。爲了提高那一點的安全性和應對那很可能不存在的假想敵嗨客,硬把跑在路由器上的 SS 換成運算量更大的 AEAD 加密會令人感覺🉐️️不償失,直到現在俺還在路由器上用着 ChaCha20 甚至是 RC4-MD5 來翻牆,因爲這樣速度能跑上 90M。視應用場景俺可以忽略 SS 的那一點疙瘩,但是搞安全的高雅人士可能就會如鯁在喉力。

而且 AEAD 加密方法也不一定能保證 SS 的安全,因爲 SS 的設計原則是儘量簡單。

SS 使用的加密密鑰全程不會變(就是你設置節點的時候輸進去的那個密碼),就算消息經過 AEAD 簽過名,你的消息也可能被拿來重放或者搞其他的小偷小摸。在 GitHub 上面有人提出了移花接木的攻擊 [ 6 ],GFW 可以暗中交換同一對 SS client 和 server 的兩條 TCP 連線,SS 可以不受影響地繼續工作,但是上層應用收到的數據可能就被調包了。

圖 6 正常工作狀態

圖 7 移花接木

俺局🉐️️這種攻擊方法在現在可能並沒有多大威脅,現在 App 大多用 TLS 加密了網路流量,發現不對勁就會中斷連線,因此你大不了就是玩 D4DJ 的時候被踢下線,沒加密的 HTTP 流量才對這種攻擊敏感。另外 GFW 也不見得會花費大功夫去調包你的 TCP,因爲這不如直接切斷連線來🉐️️簡單無腦。但是這個攻擊方法暴露出了 SS 的嚴重問題:就算有加密,牠也不能保證通訊的可靠。

另外一個問題出在 SS 的防止重放攻擊的過濾器上 [ 7 ]。SS 會觀察是否有嗨客嘗試復讀合法用戶發射的包,但是區分嗨客和合法用戶的唯一方法就是 IP 位址,因此 GFW 只需要對發送的復讀包的源地址造假一下,把自己僞裝成合法用戶,接着只需要高強度復讀,SS 服務端就會自動把合法客戶端 IP 拉嗨,之後 GFW 啥也不幹就可以橄欖這個 SS 用戶。

解決方法也不是沒有,只需要把 SS 的白名單設成 0.0.0.0/0 或者關閉防重放機能即可,但是都需要額外的操作。所幸的是 GFW 還沒有把這種攻擊方法實裝,現在的主動探測方法仍然是用中國各地的「GFW 殭屍節點」來重放(你用 tcpdump 抓一下包就可以看到巨大多這種節點的 IP),因此把 VPS 防火牆設定白名單只有自己的電腦能夠連線就可以擋住這種主動探測。可是 GFW 一旦實裝這種攻擊將會給 SS 帶來大麻煩。

**小結
**SS 一開始的設計標準就是讓流量變得沒有特徵,但是從 GFW 的角度看,在巨大多特徵明顯的 TLS 流量裏面卻有一個長時間保持連線的 TCP 還看不出這是個啥流量,該種情況無異於大街上擠滿了普通人,裏面卻混着一個全身黑袍墨鏡極力掩蓋自己的可疑傢伙。因此 SS 的這種設計哲學俺局🉐️️不是長久之計。此外 SS 還有其他弱點,俺將在下一節提到。

參考文獻
[ 5 ] Zhiniang Peng, Redirect attack on Shadowsocks stream ciphers, 📎️Link (github.com)
[ 6 ] rprx, Shadowsocks AEAD 加密方式设计存在严重漏洞,无法保证通信内容的可靠性, shadowsocks-org (github.com)
[ 7 ] rprx, 利用防重放机制自动对 Shadowsocks、VMess 等未知流量代理进行“隐蔽式拒绝服务攻击”, shadowsocks-org (github.com)

D4DJ 遭遇的困境

圖 8 神必設計邏輯

不知道該說是武士道還是🇯🇵手遊的傳統藝能吧,一是喜歡用 Unity(這哪算傳統藝能,3A 大作「元氣騎士」也是 Unity),二是喜歡在多人聯機裏面用 TCP 或 WS 來同步,我瞎猜原因可能是 TCP 代碼好寫或者 Unity 自帶了這個功能能直接抄。總之你在玩多人遊戲的時候 TCP 連線受到任何一點微小的擾動都會出現上面那種錯誤,這時如果迅速切到 Telegram 會發現能順利連線並沒有任何斷網的跡象,很明顯你是被狠狠地踢出了遊戲,並且不可以重連(俺猜這是傳統藝能之三)。

究其原因,俺局得有三點:
第一就是 SS 吃了個 TCP reset,然後內層應用層協議也被一併橄欖;
第二是 GFW 或者無良 ISP 出現了突發的連續丟包導致連線中斷;
第三就是 GFW 往 SS 包裏面加了點料,導致解密失敗了,這個包就這麼沒了(注意:這裏 D4DJ 伺服器並不會丟包重發,因爲牠已經收到過 SS 伺服器的 ACK)如圖所示:

圖 9 SS 工作示意

圖中 12,34 和 56 分別代表三條 TCP 連線,不像 iptables 轉發,TCP 端點能夠看到對端發過來的 ACK,在上圖的情況中,被代理的應用只能看到 SS 的 ACK,因此無法確定數據是否正確地傳到了對面,這個職責原本應該由 SS 來確保,其實牠卻做不到。

測試:如何橄欖 TCP 連線

GFW 最常用的方法就是丟包和 reset,丟包的原理不必多說,要是對面失聯太久那這條 TCP 怕是凶多吉少。至於 TCP reset,這是 GFW 最喜歡的切斷 TCP 的方式,效果拔群,不像丟包以後兩端會嘗試重發不斷消耗資源,reset 一旦到達終端,那終端 APP 就知道這條 TCP 已經報廢,不能再重試了,連線就這麼悄咪咪地沒了。

上面都是廢話,試一下就知道 TCP reset 是啥感覺了,現在打開命令行,要打命令力

1
curl -IiLk https://twitch.tv

你應該會看到「curl: (35) ssl_handshake returned - mbedTLS: (-0x0050) NET - Connection was reset by peer」,這就是 TCP reset 的效果。

恁可能會懷疑是 GFW 拉嗨了 twitch 的 IP,但是如果把 IP 換成沒被牆的 Cloudflare 的效果也是一樣,因爲 GFW 會看到請求裏面的 twitch.tv 然後發動 reset,嘗試:

1
curl -IiLk https://twitch.tv --resolve twitch.tv:443:104.21.61.15

你可以通過一個小實驗來證明圖 9 中,如果 34 連線遭到 reset,12 和 56 連線也會被 SS reset,因此 SS 不能保護你的 TCP 免受 reset 的攻擊,下面給出大致過程。

1
2
3
4
5
6
7
8
9
10
11
步驟
1 電腦上打開 Shadowsocks 服務端和 Wireshark
2 電腦上安裝 netwox,用來發動 reset 攻擊
3 打開電腦 nc,監聽一個端口
4 用手機連線電腦的 SS,打開手機端 nc,讓 nc 穿過 ss 代理連線電腦端
5 Wireshark 可以看到 nc 的 TCP 包,這時候用 netwox 假裝電腦 nc 發 reset
6 reset 了 SS 的連線,結果 nc 的連線也斷了

有一個小訣竅來提高成功率:
假裝成其中的一端發 reset,如果 Wireshark 上最後一個包是俺自己發的,那麼發出的 reset 的 SYN 編號應該復讀這個最後一個自己發的包的 SYN 編號。
如果 Wireshark 上看到最後一個包是對面發的,那麼發出的 reset 的 SYN 編號要復讀這個最後一個對面發的包的 ACK 編號。

如何保護 TCP 連線

俺要打 D4DJ 不被踢!!光用 SS 肯定行不通了,因此俺們針對上一節提出的三種情況來尋找方案。

丟包:這是無解的,GFW 可能豐了你的端口,也可能豐了 IP,總之沒辦法了,你應該去給那些造 GFW 的人下咒讓牠們趕快異世相遇。

TCP reset:普通人想到的方法無非就是開個 VPN,讓 SS 跑在 VPN 加密隧道裏面,因爲 VPN 一般是三層往下,所以如果隧道遭到干擾,壞掉的就不是 TCP 數據而是三層 IP 報文甚至是二層乙太網幀,而諤層三層都不提供可靠傳送,壞掉之後大不了內層 TCP 當作丟包直接重發就是了。而且利用 VPN 的加密,內層 SS 可以不用再開加密了。

圖 10 VPN 隧道,草,D-Link!

開個 VPN 又開 SS,就像安全褲裏面套短裙,脫褲子放屁。不想吃 TCP reset?那就調一下防火牆,直接把 reset 包全部擋了,還 reset 個🐓️🎱️,下面給出 iptables 防火牆的設定示範(需要 SS 客戶機和服務端都同時屏蔽 reset 才可以)。

俺們繼續拿 twitch.tv 開刀,先試試直接訪問:

1
2
root@OpenWrt:~# curl -Lik https://twitch.tv --resolve twitch.tv:443:68.183.191.74
curl: (35) ssl_handshake returned - mbedTLS: (-0x0050) NET - Connection was reset by peer

很好,死🉐️️很快,俺們把防火牆規則打進去。

1
root@OpenWrt:~# iptables -I INPUT -s 68.183.191.74 -p tcp --sport 443 --tcp-flags RST RST -j DROP

SS 服務器上也要設定:

1
iptables -d 68.183.191.74 -I INPUT -p tcp --dport 443 --tcp-flags RST RST -j DROP

然後再次嘗試:

1
2
3
4
5
6
7
8
root@OpenWrt:~# curl -Lik https://twitch.tv --resolve twitch.tv:443:68.183.191.74
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0 (Ubuntu)
Date: Wed, 10 Mar 2021 06:12:23 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
以下省略

俺們抓包看看,是不是真的沒吃 reset?下面是沒加規則的情況:

圖 11 GFW 橄欖了 TCP

看到倒數地五個包開始,GFW 連發三個 reset,這條連線就直接🈚️️了,之後真正伺服器的回包也被當作垃圾直接給 reset 掉。下圖爲加了規則以後:

圖 12 GFW 不能橄欖

俺們看到紅線處 GFW 連發三個 reset,但是都被防火牆擋下,TCP 連線能繼續運作。
這種方法雖然看上去有點迷幻,但是俺正在用 : D

GFW 篡改報文:這種情況不是光屏蔽 reset 就能解決的了,建議使用脫褲子放屁的 VPN 套 SS 方法,VPN 有完善的驗證和簽名機制,徹底保證數據正確,,,

圖 13 Sunny ◎ Showtime

DJ!! Put Your Fxxking hands up!!

VPN 遭遇的困境

前面說了兩種 VPN,一種是 UDP 實現的 WG,另一種是 TCP 爲主,UDP 輔助加速的 SoftEther。牠們都可以用來保護 SS 流量,但是首選的話還是用 WG 比較好,第一是牠的加密方式比較快,垃圾路由器也能跑;第二牠是 UDP 實現,更能模擬 IP 層的不可靠的特性,避免了用 TCP 套娃 TCP 的弊端 [ 8 ],這能提高網速,但是牠容易被牆。

SE 雖然是 TCP 協議套娃,但是大多數情況其實運行🉐️️相當不錯,不開加密的情況下能跑滿帶寬,不知道用了啥魔法,但是始終不如 WG 快。SE 速度夠用,套在裏面的 SS 速度可就不一定了,用 WG 套 SS 就不會減速。另外一個問題來源於目前大多數人的翻牆方法都是繞過中國大陸模式,即用一個列表存放所有中國的 IP,要是命中了這個列表就不走 SS。若不用 SS 而是用 VPN 翻牆,這就意味着俺們需要更改路由表,使得默認流量走 VPN,中國流量不走 VPN,但是目前還沒找到此類能配合 WG 或者 SE 去更改路由表的好方法。

而且,不容易被牆的 WG,或者速度更快但是功能不減的 SE,這種完美的 VPN 只有夢中才有。

參考文獻
[ 8 ] Why TCP Over TCP Is A Bad Idea, (inka.de)

俺🉐️️翻牆方案

這是一場貓抓老鼠的遊戲,今天能用的方法說不定明天就🈚️️了。

SS in IPv6:根據俺的觀察,IPv6 似乎還是一片淨土,牆比較矮也沒那麼多主動探測。根據之前的經驗,走 IPv6 的 SS 能在國際坦克節和兩會等 v4 SS 哀鴻遍野的特殊時期提供很穩定的連線。可惜的是,中國的各大 ISP 的 v6 網路出國線路都不好,除了教育網北京有一條 10G 直通香港 HKIX 的線路之外,其他三大運營商 v6 出國似乎都要繞很遠的路,因此找到具有合適線路的 VPS 不是一件容易的事情。

圖 14 來源 中國國家 IPv6 發展監測平臺

圖 15 中國 v6 國際出口

TLS v4 翻牆 + 主動探測防治:設定 VPS 的防火牆,只允許自己的電腦作爲白名單連入,可以有效阻擋現在 GFW 的主動探測,降低 IP 被找麻煩的概率。然後把翻牆軟件 SS 或者 V2ray 開在 443 端口假裝成 dssq 的 TLS,保持隨大流🉐️️低調姿勢才是長遠大計,有條件的也可以使用 Nginx 分流 443 的多個服務。

IPv6 上網方案:中國運營商的 IPv6 屬實用處不大,國內互聯不如 v4,國外也是,不如直接屏蔽掉。因此發燒友會用 VPN 給自己分配國外的 IPv6 地址,可以自己買一段 IP,也可以用 HE 服務免費的 IP 來建隧道。做好之後,內網設備都能直接拿到外國的 IPv6 位址,上谷歌等服務自然也是很快的(只要 VPN 不被 GFW 幹就沒問題,SE 流量由於長🉐️️很像 SSL,十分推薦用來幹這種事情)。

今日份的中國夢:希望人們能自由上網,自由做研究,自由遊玩外國遊戲的那天能早日到來。