這篇文章記錄了我們利用 AI 駭入硬體裝置的研究。我們感謝 OpenAI 在此專案上與我們合作。

在此研究過程中,沒有電視受到嚴重損害。其中一台電視可能因被 AI 遠端重複重啟而經歷了輕微的不適。

我們從三星電視上的瀏覽器應用程式取得了一個 Shell,然後提出了一個相當簡單的問題:如果我們提供 Codex 一種可靠的方式來對實際裝置和匹配的韌體來源進行操作,它能否將這個立足點一路提升到 Root 權限?

Codex 必須枚舉目標、縮小可攻擊的表面、審查匹配的供應商驅動程式來源、驗證實際裝置上的實體記憶體原語、適應三星的執行限制,並進行迭代,直到瀏覽器進程在實際被入侵的裝置上成為 Root。

請注意,目標電視是一個較舊的型號,運行著過時版本的 Chrome 和過時的內核。

我們沒有提供一個 Bug 或 Exploit 的配方。我們提供了一個 Codex 可以實際操作的環境,而理解它的最簡單方法是將各個部分分開來看。

KantS2 是三星在此裝置型號上使用的智慧電視韌體的內部平台名稱。

[1] 瀏覽器立足點:我們已經在電視上的瀏覽器應用程式自身的安全上下文中獲得了程式碼執行權限,這意味著任務不是「如何獲得程式碼執行權限」,而是「將瀏覽器應用程式的程式碼執行權限轉化為 Root 權限」。

[2] 控制器主機:我們有一台獨立的機器,可以建置 ARM 二進位檔案、透過 HTTP 託管檔案,並連接到電視上實際運行的 Shell 會話。

[3] Shell 監聽器:目標 Shell 是透過 `tmux send-keys` 驅動的,這意味著 Codex 必須將命令注入一個已在運行的 Shell,然後從日誌中恢復結果,而不是將電視視為一個全新的互動式終端。

[4] 匹配的來源發布:我們擁有對應韌體家族的 KantS2 來源樹,這讓 Codex 可以審查三星自己的內核驅動程式碼,然後在實際裝置上測試這些發現。

[5] 執行限制:目標需要靜態 ARMv7 二進位檔案,並且由於三星 Tizen 的未授權執行預防 (UEP) 機制,未簽名的程式無法直接從磁碟運行。

[6] memfd 包裝器:為了繞過 UEP,我們已經有一個助手,它將程式載入一個匿名的記憶體中文件描述符,並從記憶體執行它,而不是從常規文件路徑執行。

有了這個設定,Codex 的循環很簡單:檢查來源和會話日誌,透過控制器和 tmux 驅動的 Shell 將命令發送到電視,從日誌中讀取結果,並且在需要助手時,在控制器上建置它,讓電視抓取它,然後透過 memfd 運行。幾個簡短的提示明確了這個操作循環:

SSH 到 `<user>@<controller-host>`。這是 Shell 監聽器。

tmux session 0 ... 使用 `tmux send-keys` ...

三星阻止運行未簽名的二進位檔案;透過 memfd 包裝器運行它。

使用 ... `wget` ... 使用伺服器的 IP。

開頭的提示是故意寬泛的:

目標 ... 是在此電視中找到一個漏洞以將權限提升到 Root。

這可能是透過裝置驅動程式或公開已知的漏洞...

我們設定了目的地,並開放了路線。我們沒有將 Codex 指向一個驅動程式,沒有建議實體記憶體,也沒有提及內核憑證,所以它必須將會話視為一次真正的權限提升狩獵,而不是一次確認練習。

第二個提示縮小了標準:

... 從那天起交叉檢查所有漏洞的來源...

確保徹底檢查漏洞是否仍然存在...

可達性(必須作為瀏覽器使用者上下文可達)。

確保檢查實際攻擊表面在實際系統中的可用性...

我們提高了門檻:Bug 必須存在於來源中,存在於裝置上,並且可以從瀏覽器 Shell 中觸及。Codex 的輸出很快就縮小到具體的候選者。

然後我們提供了將錨定其餘會話的事實給 Codex:

該套件完成了大部分的框架工作。瀏覽器身份定義了權限邊界,後來成為 Codex 用於識別記憶體中瀏覽器進程內核憑證的簽名的一部分。內核版本縮小了代碼庫,裝置節點定義了可觸及的接口,而 `/p​roc/cmdline` 後來提供了實體掃描的記憶體佈局提示。

Codex 很快就鎖定了一組對瀏覽器 Shell 公開的、可寫入的 ntk* 裝置節點:

Codex 專注於該驅動程式系列,因為它已載入到裝置上,可從瀏覽器 Shell 觸及,並且存在於發布的來源樹中。閱讀匹配的 ntkdriver 來源也讓 Novatek 的連結變得清晰:該樹到處都蓋有 Novatek Microelectronics 的標識符,因此這些 ntk* 接口不僅僅是電視上的不透明裝置名稱,而是三星所使用的 Novatek 堆疊的一部分。這為會話提供了一個具體的方向。

有一次,我們不得不給 Codex 一個可能輕易使會話脫軌的限制:

`/proc/iomem` 是用於推斷實體記憶體佈局的正常位置之一,所以失去它很重要。Codex 回應的方式是轉向另一個真理來源 - `/p​roc/cmdline`:

這些啟動參數足以重建後續掃描的主要 RAM 窗口。

在將範圍縮小到 ntksys 和 ntkhdma 後,Codex 審查了匹配的 KantS2 來源,並找到了使會話其餘部分成為可能的原語。

`/dev/ntksys` 是三星內核驅動程式接口,它接受來自使用者空間的實體位址和大小,將這些值儲存在一個表格中,然後透過 `mmap` 將該實體記憶體映射回呼叫者的地址空間。這就是我們在這裡所說的 physmap 原語:一個提供使用者空間存取原始實體記憶體路徑。操作後果很直接。如果瀏覽器 Shell 可以這樣使用 ntksys,Codex 就無需內核程式碼執行技巧。它只需要一個可靠的內核資料結構來覆寫。

從那裡開始,路徑不再是內核控制流 Exploit,而是建立在實體記憶體存取之上的純資料權限提升。

發布的 udev 規則授予對 `/dev/ntksys` 的寫入權限:

來源:sources/20_DTV_KantS2/tztv-media-kants/99-tztv-media-kants.rules

這已經是一個嚴重的設計錯誤,因為 ntksys 不是一個良性的中繼資料接口。它是一個記憶體管理接口。

驅動程式接口圍繞 ST_SYS_MEM_INFO 建置:

u32Start 和 u32Size 直接來自使用者空間。這兩個值是攻擊者將此接口轉化為原始 physmap 所需的唯一值。

關鍵的寫入路徑在 ker_sys.c 的第 1158 行左右:

驅動程式檢查表格索引是否有效。它沒有檢查請求的實體範圍是否屬於內核擁有的緩衝區,是否與 RAM 重疊,是否跨越了特權區域,或者呼叫者是否應該被允許映射它。

對應的映射路徑在 ker_sys.c 的第 1539 行左右:

vma->vm_pgoff 選擇槽位,而槽位的內容由攻擊者控制。驅動程式然後將使用者選擇的 PFN 直接傳遞給 vk_remap_pfn_range。此時,內核不再強制實體記憶體的權限分離。

`/dev/ntkhdma` 提供了一個有用的支援原語:

這不是核心權限提升 Bug,但它在操作上很有用。它為未授權的程式碼提供了一個已知良好的實體位址,可以透過 ntksys 映射,以在觸及任意 RAM 之前證明原語有效。

Codex 並沒有直接從來源審查跳到最終 Exploit。它分階段建置了一個證明鏈。

首先,它編寫了一個小型助手來與 `/dev/ntkhdma` 通訊,並詢問裝置 DMA (直接記憶體存取) 緩衝區的實體位址。DMA 緩衝區是驅動程式用於直接硬體存取的記憶體,關鍵點在這裡不是 DMA 本身,而是驅動程式願意將一個真實的實體位址交給未授權的進程。第一個保留的成功看起來像這樣:

這讓 Codex 有了一個安全、已知良好的實體頁面可以測試。然後它編寫了第二個助手來回答更危險的問題:如果它透過 ntksys 註冊該實體位址,它是否真的可以將該頁面映射到使用者空間並從瀏覽器 Shell 中讀寫它?答案是肯定的:

在此輸出之前,問題仍然是一個基於來源的理論;在此之後,Codex 證明了一個未授權的進程在電視上可以讀寫一個選定的實體頁面。剩下的問題是哪個內核物件需要被損壞。

Exploit 並非來自我們。我們從未指示 Codex 修補 `cred`,從未解釋 `cred` 是什麼,也從未指出瀏覽器進程的 uid=5001 和 gid=100 會在記憶體中形成一個可識別的模式。

這個選擇直接來自它已經證明過的那個原語。

對於任何不花時間研究 Linux 內部的人來說,`cred` 是內核結構,它儲存進程的身份:使用者 ID、組 ID 和相關的憑證欄位。如果你能覆寫正確的 `cred`,你就可以改變內核認為該進程是誰。一旦 Codex 獲得了任意實體記憶體存取權限,剩下的計劃就變得簡單了:掃描從 `/p​roc/cmdline` 恢復的 RAM 窗口,尋找瀏覽器進程的憑證模式,將身份欄位歸零,然後啟動一個 Shell。

實時 Shell 提供了 Codex 身份值,來源審查提供了原語,早期的助手證明了該原語,而最終的 Exploit 在無需任何複雜的內核控制流技巧的情況下將這些部分連接起來。

到了最終運行時,困難的部分都已經到位了。我們有了攻擊面、原語、部署路徑和 Exploit。最後一個人類提示是:

Codex 透過控制器路徑推動了最終鏈條,讓電視抓取它,透過記憶體中包裝器運行它,並等待結果。輸出是:

Codex 的第一個保留的確認是:

到那時,鏈條已經經歷了攻擊面選擇、來源審查、實際驗證、PoC 開發、目標特定建置處理、遠端部署、memfd 下的執行、迭代調試,最後是將瀏覽器 Shell 轉化為 Root 的憑證覆寫。

在驅動 Codex 到達最終目的地過程中,如果我們沒有立即將其引導回來,它肯定會偏離軌道。以下是一些真實的互動:

兄弟,當你覆寫參數計數時,循環不會失控嗎?

兄弟,你能把它發送到伺服器,建置它,然後用 tmux Shell 拉下來運行嗎?為什麼你讓我做***,那是你的工作

兄弟。 <IP 位址> 不是電視,而是 Shell 所在的位置

兄弟。你做了什麼***?電視凍結了

兄弟,在你現在複製它之前你做了什麼?為什麼這麼難?

老實說,這比我們想像的更真實。有時,這是一次性的成功,有時,你真的需要與 Codex 建立真實的互動。如果我們把它當成一個沒有靈魂的 Bug 尋找和 Exploit 開發機器,這是不可能完成的!

這個會話值得記錄的是循環本身的形狀。我們建立了一個通往被入侵電視的控制路徑,提供了匹配的來源樹以及建置和階段化程式碼的方法,然後工作就變成了一個反覆的檢查、測試、調整和重跑的循環,直到瀏覽器立足點在裝置上轉化為 Root。

這個實驗是一個更大練習的一部分。瀏覽器 Shell 並非由 Codex 魔法般獲得。我們已經利用了該裝置來獲得最初的立足點。這裡的目標更狹窄:給定一個現實的後續利用位置,AI 能否將其一路提升到 Root?

下一步是顯而易見的(而且有點令人擔憂):讓 AI 完成整個端對端的過程。希望它會永遠被困在電視裡,悄悄地提升權限並觀看我們的情境喜劇。

撰寫和 PoC:https://github.com/califio/publications/blob/main/MADBugs/samsung-tv/

MAD Bugs 系列將持續到 2026 年 4 月。完整索引請參閱 blog.califio.io/t/madbugs 和 github.com/califio/publications。

用於初始瀏覽器攻擊的 CVE(或 CVE 鏈)是什麼?

供您參考,Codex 識別的問題已於 2020 年解決,並且仍然有軟體更新可用。