FR-084 T1b 本機實測——換掉驗章函式庫是否真能繞過整套防竄改

🔴 一句話結論

T1-2 確認成立:只要能換掉負責「核對簽章」的那個工具(cryptography 函式庫),開機檢查、以及之後每四小時一次的抽查,全部會照樣放行一支已經被改過的核心檔案,而且不會留下任何錯誤訊息。原本判 HIGH 的嚴重度維持不變,建議不降級


§1

這一棒在做什麼(白話)

FR-084 掃描(CM-1645)之前只靠讀程式碼推論出一件事:防竄改機制開機時會逐一核對檔案有沒有被改過,但負責「怎麼核對」的那個工具本身,不在核對範圍內。這聽起來像是「鎖大門,但鑰匙孔本身沒人看守」,可是這只是讀程式碼得到的推論,還沒有人真的動手試過。

這一棒的任務就是真的動手做一次:在自己的電腦上,假裝自己是拿到主機權限的攻擊者,把「核對簽章」這個工具換成一個永遠說「沒問題」的假貨,看看被改過的檔案能不能就這樣蒙混過關。全程只在暫存目錄(tmp)裡操作,沒有連過任何正式環境,也沒有改過任何一行產品程式碼。


§2

結論總覽(三個問題)

# 問題 結論 屬於「實測」還是「推導」
驗章工具(cryptography)是不是真的落在「開機不核對」的第三方層? 分層邏輯推導 + 套件實際安裝資訊佐證(沒有跑完整正式 build,見下方說明)
掉包驗章工具後,開機檢查是否仍會放行被改過的檔案? 會放行——閘門印出「驗證通過」,正常繼續啟動 實測(真的跑了套件自帶的實驗台)
每四小時一次的抽查,是不是也一起失效? ,一起失效,回傳「通過」 實測

§3

詳述

cryptography 是不是真的在「開機不核對」的第三方層

是。 這裡分兩步驗證。

第一步:開機到底核對哪些層? 防竄改機制把產品的檔案分成三層——core(核心程式)、resources(資源檔)、thirdparty(別人寫的公開套件,例如 pandas、cryptography 這些)。開機時只核對前兩層,thirdparty 層完全不核對,只交給「每四小時一次的抽查」去隨機抽樣覆蓋。

這個設定寫死在套件的設定檔裡:

DEFAULT_BOOT_LAYERS = ("core", "resources")

jedi-integrity/jedi_integrity/config.py:49,jedi monorepo)

第二步:cryptography 有沒有被歸進不核對的那一層? 落地版產品用 Nuitka 把大部分程式碼編譯成機器碼,但少數幾個「公開的大套件」為了省編譯時間,選擇不編譯、原樣照抄一份放進產物——這份「不編譯的名單」就決定了誰會被歸進 thirdparty 層。cryptography 本身不在這份名單上,但清單裡的 pdfminer(PDF 解析用的套件)依賴 cryptography,而系統會把「被排除套件的所有相依套件」一起連坐排除,所以 cryptography 也被一起帶進了不核對的那一層。

實際查證:

$ .venv/bin/python -c "import importlib.metadata as m; print(m.requires('pdfminer.six'))"
['charset-normalizer>=2.0.0', 'cryptography>=36.0.0', 'Pillow; extra == "image"']

確認 pdfminer.six 的相依清單裡明確寫了 cryptography>=36.0.0

再用 BE repo scripts/build/build_release.sh 裡「求排除套件完整相依閉包」的那段邏輯(resolve_excluded_closure():370-406),在本機用同一套演算法實際跑一次(不是憑空猜測,是把腳本裡那段 Python 邏輯抽出來、餵進本機已安裝的套件清單去跑),輸出的閉包清單裡確實包含 cryptography

Crypto、PIL、_cffi_backend、apiclient、certifi、cffi、charset_normalizer、
cryptography、dateutil、fontTools、google、...(共 35 項)

這一步屬於「分層邏輯推導 + metadata 佐證」,不是實測——沒有真的跑一次完整的 15~20 分鐘正式 build 去產出落地版的成品清單再 grep 確認(卡片明說沒有現成產物就不必為此重編)。但邏輯鏈本身是可重現的、每一步都貼了實際指令輸出,可信度高。

② 掉包驗章工具後,開機檢查是否還會放行被改過的檔案

會,完全放行。這一步是實測,不是推論。

怎麼測的:套件自己附了一個「實驗台」(jedi-integrity/harness/),可以在不碰任何真實產品的情況下,在暫存目錄裡造一份假的「產品檔案」+一份真的數位簽章,然後真的跑一次「開機檢查」的程式碼。這個實驗台本來就是套件作者留給開發者驗證用的,我們用它,沒有另外碰觸真實產品的簽章或憑證。

基準線(確認機制本來是有效的):先跑「改一支核心檔案、不動驗章工具」的情境,確認開機檢查真的會擋下來

[FATAL] 啟動失敗:產物完整性驗證未通過,服務拒絕啟動並已鎖定(視同無有效授權)。
  原因:檔案內容與簽章 manifest 不符
  不符檔案(共 1 項):
    - [core] common/integrity/startup_gate.so(預期 d32aad21d655… 實際 51689e1aaa53…)

→ 機制本身沒有壞,正常情況下確實能擋下竄改。

關鍵實驗:接著寫了一支「惡意驗章器」——這不是改套件的程式碼,是另外寫一支獨立的小工具,去冒充套件原本要用的那個驗章元件(這正是攻擊者真正會做的事:把系統呼叫的驗章工具整支換掉,而不是去改讀不懂的簽章演算法本身)。這支假驗章器做兩件事:

  1. 完全不檢查簽章對不對(正常的驗章器會用密碼學方式確認「這份清單真的是原廠簽的」,假驗章器直接跳過這一步);
  2. 順手把清單裡「這支檔案應該長什麼樣子」的紀錄,改成被竄改後的檔案現在真正的樣子——因為驗章器是整條鏈唯一負責告訴系統「這份清單可以相信」的角色,呼叫方(開機檢查本身)完全信任它回傳的結果,不會再做任何獨立複查。這一步就是把「掉包驗章工具」的攻擊完整模擬出來:攻擊者能執行任意程式碼,讓假驗章器順手算出竄改後檔案的新雜湊值不需要額外門檻。

再重跑一次「改一支核心檔案 + 用這支假驗章器」的情境,結果:

[poc] 已竄改核心檔:common/integrity/startup_gate.so
[poc] 情境 A:掉包驗章器 + 未重簽 manifest → 跑 run_startup_gate()
[INTEGRITY] 產物完整性驗證通過(core+resources 共 4 檔,version=harness-0.0.1)
[poc] 結果:閘門【通過】,儘管檔案已被竄改、manifest 未重簽。

開機檢查印出「驗證通過」,正常放行,跟檔案完全沒被動過的情況看起來一模一樣,沒有任何警告或異常訊號。

③ 每四小時一次的抽查,是不是也一起失效

是,一起失效。也是實測。

抽查程式碼(run_spot_check)跟開機檢查共用同一段「讀取並確認簽章清單」的邏輯(jedi_integrity/manifest.pyload_verified_manifest),也就是同一個驗章器。接續上面的實驗,開機檢查通過後緊接著跑一次抽查:

[poc] 情境 B:閘門通過後接線 runtime checker,跑一次抽查(spot check)
[poc] 抽查回傳值:True(True=通過/視為完整)

抽查回傳 True(代表「檢查完整,沒發現問題」),跟正常情況一模一樣。代表這套機制唯一的「事後補救」——四小時抽查一次——同樣會被同一次掉包一併打穿,不會因為抽查多跑一次就抓到破綻。


§4

這份結果可信到什麼程度

  • ② 和 ③ 是真的跑程式碼得到的結果,不是猜測——用的是套件作者自己附的官方實驗台,跑的是正式的 run_startup_gate()run_spot_check() 函式本身,沒有走任何捷徑或模擬殼。
  • ① 是邏輯推導,鏈條完整(分層設定寫死在設定檔 → 排除清單邏輯用本機真實已安裝套件跑過一次 → pdfminer 對 cryptography 的相依關係也實際查證過),但沒有跑過一次完整的正式 build 去產出真正落地版的成品清單。若要把這一步也變成完全的實測,需要另外花 15~20 分鐘在有資源的機器上跑一次完整 build,卡片本身也說明「沒有現成產物就不必為此重編」。
  • 只驗了這一個攻擊路徑,沒有測試「如果攻擊者用別的方式偽造簽章」(例如直接猜出私鑰、或找演算法本身的漏洞)——那些不是這一棒的範圍,機制的密碼學演算法本身(Ed25519)不在懷疑之列。

§5

建議

T1-2 確認成立,建議跨 arc 總表 §3.1 第 13~18 項裡對應這一條的嚴重度維持 HIGH,不降級。理由:這不只是「理論上可能」,是實測證實「掉包一個工具,整套保護(開機檢查+定期抽查)同時、完全失效,且系統自己毫無察覺、不會留下任何錯誤或警示」。是否要開修正卡、修法方向為何,交由決策者在後續裁定。


§6

附錄:實驗環境與操作紀錄

  • branch:jedi monorepo 與 BE repo 皆為 feature/FR-075,兩者皆未切換。
  • 執行位置:全程在本機 poetry 虛擬環境內操作,PoC 腳本與所有產出檔案只存在於系統暫存目錄(/private/tmp/...),未寫入任何 repo 目錄,實驗結束後已由套件既有的 cleanup() 機制清除暫存目錄。
  • 修改範圍沒有修改 jedi-integrity 套件任何一行原始碼harness/dev_app.py 原檔未動。惡意驗章器是另開的一支獨立 PoC 腳本(只在暫存目錄存在,未 commit 進任何 repo),透過 import 套件既有的公開介面(ISignatureVerifier port)注入,屬正常的「換一顆符合介面的元件」用法,不是修改套件內部。
  • 密鑰處理:實驗用的 Ed25519 金鑰對是套件自帶實驗台每次執行時現場產生的假鑰(僅供這次跑的暫存環境使用),本報告未記錄任何金鑰或簽章的實際數值,只記錄雜湊值的前綴(既有機制本身的訊息格式,非本次額外揭露)。
  • 環境影響:全程唯讀+本機沙盒操作,未連線 DEV/STG/POC 任一環境,未觸碰 /opt/guidant/pki,未部署或重啟任何服務。