Apache mod_http2 爆重大 RCE 漏洞:CVSS 9.8,實測修補與緩解效果

in , ,
閱讀時間: 12 分鐘

Apache HTTP Server 專案於 11 月 11 日發布 2.4.71,修補 mod_http2 模組中編號 CVE-2026-119618 的重大漏洞。官方公告將其列為 critical,標題直接寫明「heap corruption and RCE in assign_headers」,assign_headers() 函式存在同步不當的競態條件(CWE-362),可導致堆積記憶體毀損,進而遠端執行程式碼。受影響範圍是 2.4.55 到 2.4.70,從 GitHub 取得的獨立版模組 mod_h2,2.0.8 到 2.0.42 同樣受影響。攻擊者不需要認證,只要能以 HTTP/2 連上伺服器即可嘗試觸發。

Apache mod_http2 重大漏洞實測:版本中標不等於曝險,停用 HTTP/2 效能只差 13%

Red Hat 給出 CVSS 3.1 基本分數 9.8(AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H),並在說明中表示已有公開研究對預設設定且啟用 mod_http2 的伺服器示範可靠的利用。Red Hat 與 Amazon Linux 評為 CVSS 9.8。

這個漏洞的另一個話題是發現者,Apache 公告的致謝名單第一位是 Anthropic 的 OSS Scanner(內部編號 ANT-2026-MAPKT6MZ),於 10 月 26 日通報,Google Cloud Vulnerability Research 的 Anthony Weems 與 Simon Scannell 則在 11 月 3 日獨立通報。兩組人馬在一週內撞到同一個洞,從第一份通報到修補發布約兩週。

對維運人員來說,比起誰發現的,更實際的問題是三個:

  1. 手上的 Apache 到底有沒有開 HTTP/2?版本落在範圍內就一定中招嗎?
  2. 官方沒寫 workaround,社群建議的「從 Protocols 拿掉 h2 與 h2c」實際上擋不擋得住?有沒有容易漏掉的地方?
  3. 暫時關掉 HTTP/2,網站會慢多少?

CyberQ 實測與整理漏洞與各發行版修補現況,再以 Docker 建立 httpd 2.4.70 與 2.4.71 的對照實驗室,驗證協定協商、因應措施與效能代價,最後用自製的唯讀檢查腳本盤點幾台實際運作中的 web 主機。全文不包含、也沒有執行任何攻擊程式,實驗只送出正常的 HTTP 請求。

漏洞機制的修補只有一行

上游修補是 commit 824beab9b9(PR #975、#977),只改了 modules/http2/h2_request.c 中的一行:

/* If we have a content-type, but already seen eos, no more
 * data will come. Signal a zero content length explicitly.
 */
-  apr_table_setn(req->headers, "Content-Length", "0");
+  apr_table_setn(r->headers_in, "Content-Length", "0");

assign_headers() 負責把 HTTP/2 串流的請求標頭轉成 Apache 內部的 request_rec。當請求帶有 Content-Type 但串流已經結束(不會再有本文),模組會補一個 Content-Length: 0。舊程式把這個標頭寫進 req->headers,也就是屬於 HTTP/2 串流物件 h2_request 的標頭表;修補後改寫到這次請求自己的 r->headers_in。

從修補內容與 Red Hat 的說明可以推論問題所在,h2_request 的標頭表不屬於處理這次請求的工作執行緒,修改它等於在沒有同步保護的情況下,從另一個執行緒、用另一個記憶體池去改共用的資料結構。HTTP/2 的多工特性讓多條串流同時在不同執行緒上處理,時序一旦對上就會毀損堆積。

Red Hat 也特別說明,RHEL 9 與 10 的 mod_http2 為每條串流使用獨立的記憶體配置器,所以在這兩個版本上評為 Important 而非 Critical;RHEL 8 以前的 mod_http2 早於 2.0.8,沒有這段程式碼,不受影響。

影響範圍從 2.4.55 開始也與此吻合,httpd 從該版起內附的 mod_http2 換成 2.0 系列,對應獨立版 2.0.8 之後才出現的這段程式碼。

11 月 12 日更新:社群 PoC 已重現記憶體毀損,但尚未展示完整 RCE

截至 2026 年 11 月 12 日,GitHub 已出現針對 CVE-2026-119618 的公開概念驗證程式(PoC)。研究者 googlesky 在 CVE-2026-119618 專案中,使用 Podman 建立隔離實驗室,搭配 AddressSanitizer(ASan)與 ThreadSanitizer(TSan),對 Apache httpd 2.4.70 與已修補的 2.4.71 進行對照測試。

依研究者公布的紀錄,2.4.70 在 6,080 次 HTTP/2 請求中出現 5 筆 ASan 記憶體錯誤報告,以及 31 筆與 assign_headers() 有關的 TSan 記憶體配置競態報告,包括 heap-use-after-free 與程序崩潰;相同測試條件下,2.4.71 未再出現對應的記憶體毀損與配置競態。研究者也驗證,將 Protocols 改為 http/1.1 後,HTTP/2 請求會遭拒絕,與 CyberQ 本次緩解實測結果一致。

需要強調的是,這份 PoC 已提供堆積記憶體毀損與競態條件的重現證據,但尚未展示成功執行任意程式碼的完整 RCE 攻擊鏈。Red Hat 雖在官方說明中表示已有公開研究證實可靠利用,但目前可查閱的這份 PoC,證據仍停留在記憶體毀損與程序崩潰層級。因此,不能將 PoC 公開直接等同於完整 RCE 利用程式已經公開。上述結果來自研究者提供的紀錄,CyberQ 本次實測並未執行攻擊程式,也未獨立重現記憶體毀損。

影響範圍與修補現況(2026 年 11 月 12 日)

項目狀態
Apache httpd 上游2.4.71 已修補(11/11)
獨立版 mod_h2(GitHub icing/mod_h2)2.0.8 到 2.0.42 受影響,專案已於 2026 年 6 月 9 日封存,不會再出新版
Red Hat評為 Critical、CVSS 9.8;RHEL 9/10 評 Important,RHEL 8 以前不受影響
Debianbookworm、trixie、forky 仍標示 vulnerable,sid 的 2.4.71-1 已修補
Ubuntu 24.04 官方套件庫最新仍是 2.4.58-1ubuntu8.18(11/09 發布,早於本漏洞公開),尚無修補版,Ubuntu CVE 頁面在撰文期間持續逾時
ondrej/apache2 PPAnoble 與 jammy 已上架 2.4.71

同一版 2.4.71 另外修了兩個漏洞,mod_md 的 NULL 指標解參考(CVE-2026-106023,important,2.4.30 起受影響)與 mod_vhost_alias 的 1 位元組堆疊溢寫(CVE-2026-109163,low,僅 2.4.69 與 2.4.70)。

使用獨立版 mod_h2 的環境要特別留意,上游已經不維護,等不到修正版,只能改用 httpd 2.4.71 內附的 mod_http2,或停用 HTTP/2。

實驗室設計

CyberQ 實驗在一台 Ubuntu 24.04 主機上進行,全部跑在不對外開放埠號的 Docker 內部網路(docker network create --internal):

  • 伺服器使用官方 httpd:2.4.70 與 httpd:2.4.71 映像,event MPM,載入 mod_http2 與 mod_ssl,TLS 用自簽憑證。Protocols 的值由容器環境變數帶入,方便切換。
  • 用戶端採用 Alpine Linux 容器內的 curl 8.14.1、OpenSSL 3.3.7 與 h2load(nghttp2 1.62.1)。
  • 每組設定都測四件事,TLS 的 ALPN 是否選 h2、curl --http2 走 HTTPS 的結果、h2c 直連(prior knowledge)、h2c 升級(Upgrade: h2c)。

實測一:版本號是唯一可靠的依據,模組版本不是

兩個映像啟動時,mod_http2 在日誌中印出的版本完全相同:

[http2:info] AH03090: mod_http2 (v2.0.42, feats=CHPRIO+SHA256+INVHD+DWINS, nghttp2 1.64.0), initializing...

2.4.70 與 2.4.71 內附的 mod_http2 都自稱 v2.0.42,修補那一行並沒有讓模組版本號跟著跳。換句話說,用 mod_http2 版本判斷是否已修補是無效的。上游編譯的版本要看 httpd -v,發行版套件則會把修補回溯到舊版號上(例如 Ubuntu 的 2.4.58),要看套件 changelog 是否列出 CVE-2026-119618。

實測二:Protocols 決定一切

httpd 2.4.70 與 2.4.71 在三種 Protocols 設定下的協商結果
圖一:兩個版本、三種 Protocols 設定與未載入模組的協商結果。紅字表示協商出 HTTP/2,綠字表示只剩 HTTP/1.1。

結果整理如下:

Protocols 設定TLS ALPNh2c 直連h2c 升級
h2 h2c http/1.1h2成功成功
h2 http/1.1h2失敗忽略,回 HTTP/1.1
http/1.1http/1.1失敗忽略,回 HTTP/1.1
h2 h2c http/1.1 但未載入 mod_http2http/1.1失敗忽略,回 HTTP/1.1

幾個實測的小心得:

  • Apache 2.4.70 與 2.4.71 在協商行為上完全一致,修補不影響正常的 HTTP/2 功能。
  • 只拿掉 h2 而保留 h2c,明文 HTTP 埠仍然可以用 HTTP/2 連進來;h2c 是很多人會忘記的那一半。Red Hat 的說明也明確指出,只要 Protocols 啟用 h2 或 h2c 就受影響。
  • Protocols 改成 http/1.1 後,兩種 h2c 方式都失敗、ALPN 只剩 http/1.1,網站照常回應 200。
  • 沒有載入 mod_http2 時,Protocols 裡寫著 h2 也不會報錯,Apache 會靜默退回 HTTP/1.1。因此 a2dismod http2 也是有效的緩解方式。

這裡有一個實作細節,CyberQ 的實作設定裡有 LogLevel http2:info,模組一拿掉 Apache 就以 Cannot find module http2 拒絕啟動。實務上若選擇停用模組,要先確認設定檔中所有 H2* 指令與 http2: 日誌層級都包在 <IfModule http2_module> 裡,否則重新載入會失敗,變成自己把網站關掉。

實測三:只改全域設定的陷阱

Protocols 可以寫在伺服器層級,也可以寫在每個 <VirtualHost> 裡,後者會覆寫前者。我們把全域改成 http/1.1,但讓 TLS 站台保留自己的 Protocols h2 http/1.1:

全域 Protocols http/1.1 但 VirtualHost 保留 h2 時的協商結果
圖二:全域已改成 http/1.1,TLS 站台仍協商出 h2。

結果 TLS 依然協商出 h2。很多由控制台或自動化工具產生的站台設定(例如申請憑證時一併寫入的 SSL vhost),都會在 vhost 裡帶自己的 Protocols,只改 mods-available/http2.conf 或主設定檔會以為已經處理完畢。

Debian 與 Ubuntu 的使用者還要知道另一件事,套件內附的 /etc/apache2/mods-available/http2.conf 唯一一行有效設定就是

Protocols h2 h2c http/1.1

也就是說,在這兩個發行版上執行 a2enmod http2,就等於對所有站台同時開啟 h2 與 h2c。

正確的檢查方式是把所有被載入的設定檔都掃一遍,再實際連線確認:

# 列出所有被載入的設定檔,再找出每一行 Protocols
apache2ctl -t -D DUMP_INCLUDES
grep -rn '^\s*Protocols' /etc/apache2/

# 實際確認 TLS 與明文是否仍會協商出 HTTP/2
echo | openssl s_client -connect 127.0.0.1:443 -servername www.example.com -alpn h2,http/1.1 2>/dev/null | grep ALPN
curl -s --http2-prior-knowledge -o /dev/null -w '%{http_version}\n' http://127.0.0.1/

openssl s_client 要帶正確的 -servername,因為 Protocols 是依站台套用的,用 IP 連線只會測到預設站台。

實測四:關掉 HTTP/2 會慢多少

緩解措施的代價是失去 HTTP/2。我們用 h2load 在 2.4.71 上量兩種情境(只送正常請求,一個首頁加 30 個約 5.5 KB 的靜態檔,共 31 個資源):

關閉 HTTP/2 前後的頁面載入時間與吞吐量
圖三:左為單頁 31 個資源在 40 ms 往返延遲下的完成時間,右為無延遲時的吞吐量。

單頁載入(用戶端加 40 ms 延遲,含 TLS 交握,各 5 次中位數)

協定與連線方式完成時間
HTTP/2,1 條連線、31 條串流325 ms
HTTP/1.1,6 條連線(瀏覽器對同一主機的常見上限)369 ms
HTTP/1.1,1 條連線1,390 ms

純吞吐(無延遲,20 條連線,20 萬請求,各 3 次中位數)

協定與連線方式每秒請求數
HTTP/2,每連線 10 條串流39,392
HTTP/2,每連線 1 條串流77,696
HTTP/1.1,不管線化86,007

在有延遲的網路上,HTTP/2 的多工確實有幫助,但瀏覽器本來就會對同一主機開 6 條 HTTP/1.1 連線,實際差距約 13%,而不是單連線那種 4 倍落差。在沒有延遲的吞吐測試中,HTTP/1.1 反而略快,mod_http2 在本機迴路上多條串流並行時還有額外的排程成本。

結論是對大多數網站而言,暫時把 Apache 退回 HTTP/1.1 的使用者體驗影響很小,遠小於冒著 RCE 風險撐到套件更新。另外,如果 Apache 前面已經有 nginx、CDN 或負載平衡器終止 HTTP/2,訪客端的協定根本不受影響。

實測五:實際主機盤點

CyberQ 把上述檢查寫成唯讀檢查程式碼,在機器上讀版本、確認 mod_http2 是否載入、掃描所有被載入設定檔中的 Protocols、查套件 changelog 是否已含本 CVE 的修補,最後對每個監聽埠實際做一次 ALPN 與 h2c 探測,以探測結果下判斷。這個程式碼也可以從外部對指定主機做遠端探測。

本次在實驗室自我測試時就抓到一個靜態檢查的盲點,我們的設定檔用 Protocols ${H2_PROTOCOLS} 這種變數寫法,單純 grep 看不出實際值。所以腳本遇到間接寫法時,一律以實際連線探測為準。

接著以只讀不改的方式盤點客戶和實際運作中的幾台主機(以 A 到 F 代稱):

主機環境Apache 版本mod_http2對外架構判定
AUbuntu 24.042.4.58-1ubuntu8.18未載入nginx 終止 TLS 與 HTTP/2,Apache 只在後端不受影響
BUbuntu 24.042.4.69(ondrej PPA)未載入同上不受影響,PPA 已有 2.4.71 可升
CUbuntu 24.042.4.58-1ubuntu8.18未載入CDN 與雲端負載平衡器,原站只開 80不受影響
DUbuntu 24.042.4.58-1ubuntu8.18未載入同上不受影響

四台 Linux 主機的版本都落在受影響範圍內(Ubuntu 2.4.58 與 PPA 2.4.69),Ubuntu 官方也還沒有修補版,但 mod_http2 都沒有載入,HTTP/2 由前端的 nginx 或雲端服務處理,Apache 只講 HTTP/1.1,因此不受影響。這種版本在範圍內、但沒有可觸及的路徑的情況,是盤點時最常見的結果,也說明了只看版本號會高估風險。

維運建議清單

  1. 先判斷有沒有可觸及的 HTTP/2 路徑,而不是只看版本。版本在 2.4.55 到 2.4.70、mod_http2 已載入、且任何一處 Protocols 含 h2 或 h2c,三者同時成立才受影響。以實際連線探測為準。
  2. 能升級就升級。自行編譯或使用 ondrej PPA 的環境,直接換 2.4.71,RHEL 9/10 套用 Red Hat 已發布的勘誤,Debian 穩定版與 Ubuntu 官方套件尚未修補,要持續關注。發行版套件以 changelog 是否列出 CVE-2026-119618 為準,不要看 mod_http2 版本。
  3. 暫時無法升級時,關掉 HTTP/2。 二擇一:
    • 把所有 Protocols 改成 http/1.1,包含每個 VirtualHost 內的設定。只拿掉 h2 不夠,h2c 也要拿掉。
    • 或直接停用模組(Debian 系為 a2dismod http2),先確認沒有未包在 <IfModule> 內的 H2* 指令或 http2: 日誌設定,再以 apache2ctl configtest 驗證後重新載入。
  4. 前端已有反向代理或 CDN 的架構,確認它連回 Apache 時用的協定。前端終止 HTTP/2 後若以 HTTP/1.1 連回原站,Apache 這一段不受影響;但部分 CDN 與負載平衡器提供以 HTTP/2 連回原站的選項,開啟時原站仍可被觸及。
  5. 使用獨立版 mod_h2 的環境,改用內附模組。mod_h2 已封存,不會有修正版。
  6. 盤點設備裡的內嵌 Apache。包括 NAS、防火牆、印表機、各類管理介面常內建 Apache,版本更新取決於設備廠商。至少先把這類管理介面限制在管理網段。

緩解完成後的驗證方式,就是重做實測三的兩條指令,ALPN 只剩 http/1.1,h2c 直連失敗,網站仍正常回應。

實務建議

CyberQ 認為,CVE-2026-119618 的修補只有一行,但它提醒了幾件盤點時常被忽略的事:HTTP/2 不只走 TLS,明文的 h2c 同樣是入口,Protocols 可以藏在每個站台的設定裡,內附模組的版本號不會因修補而改變,最容易被遺忘的反而是許多設備內建的 Apache 管理介面網頁。

實務上,只看 Apache 版本號只能告訴你需要更新的可能性,但真的去實際連線探測才能告訴你是否有曝險。

延伸閱讀