透過 eBPF 攔 TLS 連線的明文

在「Capturing Linux SSL/TLS plaintext without a CA certificate using eBPF (github.com/gojue)」這邊看到的工具,可以透過 eBPF 直接攔 TLS 連線的明文,專案在 gojue/ecapture 這邊可以看到。

除了支援 OpenSSL,還支援了 GnuTLSNSS,看起來常見的 library 都有支援。

算是 reverse engineering 的工具,看起來會適合用在應用程式有 pinning 的情況下 (像是 CA pinning,或是 certificate pinning),有機會省下改 binary 的麻煩。

官方說明中有提到支援 Android + arm64 這點應該也算清楚。

蘋果出手幹掉 Beeper Mini 了

前幾天在「Android 上與 Apple 生態系 iMessage 互通的 app」這篇提到的 Beeper Mini 被蘋果幹掉了:「Apple cuts off Beeper Mini’s access after launch of service that brought iMessage to Android」。

目前的 update 看起來要想辦法繞?

所以看起來蘋果的態度沒有要放,然後接下來應該會貓捉老鼠?不過蘋果的機器上面有硬體可以認證,真的把 iMessage 接上資料庫驗證的話應該就繞不過了...

Android 上與 Apple 生態系 iMessage 互通的 app

Hacker News 上兩篇相關的可以一起看,首先是 Beeper Mini,一套在 Android 上直接與 Apple 生態系 iMessage 相通的 app,而且不需要另外的 Apple 設備當作 Proxy:「Show HN: Beeper Mini – iMessage Client for Android (beeper.com)」。

另外先提一下,這是一套付費軟體 ($1.99/mo),考慮到這算是 reverse engineering 後的產品,不確定 Apple 會不會反制,要付錢使用的人心裡先有個底:

We currently offer a 7 day free trial, afterwards there is a $1.99 per month subscription.

另外一篇相關的是「iMessage, explained (jjtech.dev)」,原文是今年八月的文章,應該就是 Beeper Mini 那篇而被貼出來的關係,在「iMessage, explained」這裡。

裡面解釋了他自己實作 pypush 時怎麼處理 iMessage 的部分:

This blog post is going to be a cursory overview of the internals iMessage, as I’ve discovered during my work on pypush, an open source project that reimplements iMessage.

專案裡面有提到 Apple 在這邊有段 obfuscated code,由於只有註冊階段需要用到,他選擇直接跑環境起來執行,產生出對應的 data 後就不用再跑,也就省掉 reverse engineering 這塊功夫:

pypush currently uses the Unicorn CPU emulator and a custom MachO loader to load a framework from an old version of macOS, in order to call some obfuscated functions.

This is only necessary during initial registration, so theoretically you can register on one device, and then copy the config.json to another device that doesn't support the Unicorn emulator. Or you could switch out the emulator for another x86 emulator if you really wanted to.

另外一個先前的消息是 Apple 說要支援 RCS:「Apple announces that RCS support is coming to iPhone next year」,目前大家的猜測是跟歐盟一直在要求 Apple 開放 iMessage 有關。

Tailscale Funnel 公開測試

去年 11 月的時候寫過 Tailscale Funnel 的消息:「Tailscale 也推出類似 Cloudflare Tunnel 的產品,Tailscale Funnel」,剛剛則是宣佈公開測試:「Tailscale Funnel now available in beta」。

測了一下,設定不算太難,但有些步驟要做:

  • 在網頁上先允許 Access Controls 內的 Funnel。
  • 然後允許 DNS 內的 HTTPS Certificates。
  • 剩下就是照著文件跑,在本地跑對應的指令。

他的想法是把 *.ts.net 這個網域拿出來 internet 上面用,但他希望 Let's Encrypt 簽的 SSL key 應該要放在本地端,而不是讓 Tailscale 看到內容。

但同樣也考慮到使用者的體驗,Tailscale 不需要使用者自己處理 SSL certificate 一堆事情,而是實做在 tailscaled 這隻程式裡面,讓本地端的程式還是走 HTTP 而非 HTTPS。

對應的,使用者如果想要取得對應的 key 與 cert,也可以透過 tailscale cert 指令取得。

測了一下位置,HiNet 的使用者會透過東京的節點轉進來,拿來跑測試開發機應該是夠用。

以他的用法來說,跟 Cloudflare Funnel 的定位不太一樣,反倒是擠壓 ngrok 這類服務。

Tailscale 也推出類似 Cloudflare Tunnel 的產品,Tailscale Funnel

Tailscale 也推出了類似 Cloudflare Tunnel 的產品,叫做 Tailscale Funnel:「Introducing Tailscale Funnel」。

都是透過 server 本身主動連到 Cloudflare 或是 Tailscale 的伺服器上,接著外部的 request 就可以繞進來了。

不過 Tailscale Funnel 的定位跟 Cloudflare Tunnel 有些差異,看起來 Tailscale Funnel 比較偏向給 dev/stage 環境的用法,Cloudflare Tunnel 像是要跑在 production 的設計?

目前是 alpha 階段,有些限制,像是目前能開的 port:

The ports you can specify to expose your servers on are currently to 443, 8443 and 10000.

另外從技術面上看起來一定得用 TLS 連線,因為他得透過 TLS 的 SNI 資訊來決定是誰:

We can only see the source IP and port, the SNI name, and the number of bytes passing through.

對於已經有用 Tailscale 的使用者來說好像可以玩看看,但另外一點是 Cloudflare 的機房密度很高,這點可能是 Tailscale 也要想一下的問題?

Decompile to C 的工具

昨天在 Hacker News 上看到「Decompiler Explorer (dogbolt.org)」這篇,裡面列出了很多 Decompile to C 的工具 (就不用直接硬看 assembly),包括了 open source 與商用軟體:

網站本身則是提供界面可以交叉比較,不過各家的結果看起來還是有侷限...

試用 Cloudflare 的 Argo Tunnel

Cloudflare 宣佈讓大家免費使用 Argo Tunnel 了,也順便改名為 Cloudflare Tunnel 了:「A Boring Announcement: Free Tunnels for Everyone」。

Starting today, we’re excited to announce that any organization can use the secure, outbound-only connection feature of the product at no cost. You can still add the paid Argo Smart Routing feature to accelerate traffic.

As part of that change (and to reduce confusion), we’re also renaming the product to Cloudflare Tunnel. To get started, sign up today.

Cloudflare Tunnel 的功能就像 ngrok,在用戶端的機器上跑一隻 agent 連到 Cloudflare 或是 ngrok 的伺服器,這樣外部連到 Cloudflare 或是 ngrok 的伺服器後就可以透過這組預先建好的連線連上本機的服務了,常見的應用當然就是 HTTP(S) server。

本來是付費功能,一般使用者應該也不會需要這個功能,這次把這個功能免費丟出來的用意不知道是什麼...

不過既然都免費了,還是花了點時間測了一下,可以發現 ngrok 的設定比較簡單,Cloudflare 的 cloudflared 設定起來複雜不少,不過文件還算清楚,照著設就好。

Anyway,有些事情有了 Cloudflare Tunnel 就更方便了,像是有些超小型的 VPS 是共用 IPv4 address 而且沒有 IPv6 address 的,可以透過 cloudflared 反向打進去提供服務,同樣的,在 NAT 後面的機器也可以透過這個方法很簡單的打通。

順便說一下,現在的 blog.gslin.org 就是跑在 cloudflared 上面了,官方提供的 ARM64 binary 跑在 EC2t4g 上面目前看起來沒有什麼問題,而且比起本來 nginx 都是抓到 Cloudflare 本身的 IP,現在加上這兩行後反而就可以抓到真的使用者 IP address 了:

    set_real_ip_from 127.0.0.1;
    real_ip_header X-Forwarded-For;

跑一陣子看看效果如何...

GTA 的啟動讀取效能問題

這件事情也已經過了一個禮拜,來整理一下發生什麼事情...

起因是 GTA Online 的遊戲開啟速度很慢,而有人一路 reverse engineering 找出問題並且解決:「How I cut GTA Online loading times by 70%」,對應的 Hacker News 討論有提到其他有趣的事情也可以看看:「How I cut GTA Online loading times by 70% (nee.lv)」。

作者的電腦不算太差,但光開啟 GTA Online 就需要六分鐘,網路上甚至有辦投票蒐集大家的等待時間,發現也有很多人反應類似的問題:

接下來就開始 reverse engineering 了,先觀察各種狀態後發現是卡在 CPU,而不是網路或 Disk I/O,然後就拿出 Luke Stackwalker 這個工具 profiling,不過因為沒有 debug symbol 幫忙 group,所以只能人工判斷後,可以看到兩個問題:

第一個問題發現效能是卡在 strlen(),而 call stack 可以看出來是從 sscanf() 一路打進去的:

反追發現是在處理 10MB 的 JSON 檔造成的,裡面 sscanf() 因為拉出 strlen(),於是就造成把整個 10MB 的 JSON 掃過很多次 (一開始是 10MB,掃到後面會愈來愈少,平均下來應該是 5MB):

第二個問題產生的時間會在第一個問題跑完後,另外看問題的性質,應該跟第一個 JSON 處理有關,他會把 JSON 處理過的資料丟進 array,每個 entry 長這樣:

struct {
    uint64_t *hash;
    item_t   *item;
} entry;

丟進 array 是 OK 的,但問題在於他需要判斷 entry 是否重複,卻沒有用 hash 或是 tree 的結構,而這邊大約有 63k 筆資料,用 array 實做就產生了 O(n^2) 的演算法:

But before it’s stored? It checks the entire array, one by one, comparing the hash of the item to see if it’s in the list or not. With ~63k entries that’s (n^2+n)/2 = (63000^2+63000)/2 = 1984531500 checks if my math is right. Most of them useless. You have unique hashes why not use a hash map.

作者在 PoC 的章節裡面描述他怎麼解這兩個問題。

第一個問題比較好的解法是修正 JSON Parser,但這太複雜,所以他用 workaround 解:把 strlen() 包起來,針對長字串加上一層 cache:

  • hook strlen
  • wait for a long string
  • “cache” the start and length of it
  • if it’s called again within the string’s range, return cached value

而第二個問題他直接把檢查是否有重複的跳過,因為資料本身不重複:

And as for the hash-array problem, it’s more straightforward - just skip the duplicate checks entirely and insert the items directly since we know the values are unique.

整個開啟的速度從六分鐘降到一分五十秒,還是偏慢,但算是大幅緩解的 GTA Online 啟動速度的問題了。

不過故事到這邊還沒結束,有人一路去挖,發現其實 sscanf() 的效能地雷已經不是第一次了:YAML 的 Parser 也中過一樣的問題:「Parsing can become accidentally quadratic because of sscanf」,這篇也一樣上了 Hacker News:「Parsing can become accidentally quadratic because of sscanf (github.com/biojppm)」。

然後這又帶出了六年前在 StackOverflow 上就有人問過這個問題:「Why is glibc's sscanf vastly slower than fscanf on Linux?」。

另外也有人整理出來,應該是大家把同樣的演算法拿來實做:

JdeBP 3 days ago

I found this while making a collection of what C implementation does what at https://news.ycombinator.com/item?id=26298300.

There are two basic implementation strategies. The BSD (FreeBSD and OpenBSD and more than likely NetBSD too), Microsoft, GNU, and MUSL C libraries use one, and suffer from this; whereas the OpenWatcom, P.J. Plauger, Tru64 Unix, and my standard C libraries use another, and do not.

The 2002 report in the comp.lang.c Usenet newsgroup (listed in that discussion) is the earliest that I've found so far.

後續的更新動作可以再追一下進度 (包括 GTA Online 與各家的 libc)。

將本機開發網站展示給外部看的工具 inlets

要講 inlets 前要先講 ngrok 這個服務。這個服務可以在開發機上主動建立連線到外部伺服器,接著透過這個連線與本機的 web server 溝通,讓外部的客戶可以很方便的進行測試 (通常會開個 Zoom 之類的工具邊討論邊修改),算是 reverse proxy as a service 的服務。

類似機制的服務還有 CloudflareArgo Tunnel,不過產品定位不太一樣。

而 inlets 就是 open source 版本的 ngrok,你只要在外部租一台主機就可以用了。左邊是自己的開發機 (像是 Macbook),右邊則是外部的主機 (租用 VPS):

不過這個跟開發模式也有關...