Day 18 已經知道,CAN 常位於攻擊路徑的車內階段。
攻擊者通常要先從診斷接口、外接設備或對外連線元件取得初始能力,再跨越 Gateway 或直接接觸目標 CAN 區段。
假設現在有一個未受信任的節點,已經能在同一段 CAN Bus 上傳送 Frame。
它不必先取得某顆 ECU 的網路地址,因為基礎 CAN Frame 根本沒有獨立的來源地址欄位。
只要送出接收端正在使用的 Identifier、正確長度與可被應用程式接受的 Data,另一顆 ECU 就可能把它當成同一類訊息處理:
合法 ECU
→ 發布「車門已上鎖」
未受信任節點
→ 使用相同 Identifier 發布「車門未上鎖」
接收 ECU
→ 看見兩筆格式正確的 Frame
→ 若沒有額外來源、新鮮度與合理性檢查
→ 可能採用後來收到的狀態
這就是今天要分析的 CAN Injection(CAN 訊息注入)。
我們會先把 Injection、Spoofing 與 Replay 分清楚,再回到 Day 07 建立的 vcan0/ICSim 環境,找出一筆模擬車況訊息,送入一筆單次測試 Frame,最後比較注入前後的儀表狀態與 candump 紀錄。
讀完這篇文章,你應該能夠:
vcan0/ICSim 中辨識一筆車況訊息並完成單次注入candump 紀錄、注入前後畫面與防護假設留下實驗證據本文所說的 CAN Injection,是一個具有傳送能力的節點,主動把自己建立的 CAN Frame 送進目標網路區段。
它可能使用:
所以 Injection 描述的是把 Frame 送進 Bus 的動作。
如果注入節點刻意使用原本屬於另一項功能或另一個 ECU 的訊息外觀,讓接收端誤認資料來源或語意,便同時形成 **Message Spoofing(訊息偽冒)**情境。
兩個詞可以出現在同一條路徑上,卻不是完全相同的概念。
| 名稱 | 本文使用方式 | 教學例子 |
|---|---|---|
| Injection | 主動建立 Frame 並送進 CAN Bus | 送出一筆指定 ID 與 Data 的新 Frame |
| Spoofing | 讓訊息看起來屬於另一個來源或功能 | 使用原本的車門狀態 ID,宣告錯誤狀態 |
| Replay | 把先前觀察或記錄的有效 Frame 再次送出 | 重送舊的解鎖或診斷訊息 |
| Modification | 改變資料內容後再傳送 | 保留大部分 Data,只修改狀態 bit |
一筆攻擊可能同時具有多種特性。
例如,攻擊者先記錄一筆舊的解鎖 Frame,再把它送回 Bus,這既是 Injection,也是 Replay。
今天專注在「依觀察結果建立一筆錯誤狀態 Frame」的 Injection/Spoofing。
完整 Record/Replay 與新鮮度問題留到 Day 20。
Day 03 到 Day 05 已經拆過 CAN 的三項特性:
這不表示 CAN 沒有可靠性機制。
CAN Controller 仍會處理 bit stuffing、CRC、ACK、Error Detection 與 Retransmission。
問題是,這些機制原本要處理傳輸可靠性,不是辨識誰有權送出某種語意。
CRC 是 Cyclic Redundancy Check,也就是循環冗餘檢查。
一般使用 cansend 搭配實體 CAN 介面時,不需要自己把 CRC byte 寫進 Data。
實體 CAN Controller 會依 Frame 內容建立 CRC 等低層欄位。
vcan 的邊界則不同。
它在 Linux Kernel 中交換抽象的 CAN Frame,不模擬 CAN_H/CAN_L、實際 bit timing、線路 CRC、ACK、仲裁與 Error Frame。
所以今天的實驗能驗證 Application 收到相同 ID/DLC/Data 時如何反應,不能拿來量測實體 CAN Data Link 的行為。
因此,一個能建立任意 CAN Frame 的節點,也能送出具有正確 CRC 的偽造內容。
內容由合法 ECU 建立 + CRC 正確
與
內容由注入節點建立 + CRC 正確
在傳輸錯誤檢查這一層都可能成立
CRC 沒有祕密金鑰,不能證明 Frame 來自原本被分配該 Identifier 的 ECU。
Bus 上的 ACK 表示至少有另一個節點正確收到 Frame。
它不能證明:
CAN Controller 的 Acceptance Filter 可以讓 ECU 只把特定 Identifier 交給上層處理。
如果合法 ECU 和注入節點都使用相同 ID,兩筆 Frame 都符合相同的 Filter 條件。
Filter 可以降低不相關訊息帶來的處理負擔,卻不能只靠 ID 判斷真正 Sender。

圖 1:CAN Bus 能處理 Frame 格式、仲裁與傳輸錯誤,但接收端仍要在更高層驗證來源、新鮮度及內容合理性
看到 cansend 可以送出 Frame,不代表任何外部攻擊者都能控制任何車輛。
一條合理的 CAN Injection 路徑至少要確認:
| 條件 | 要驗證的問題 |
|---|---|
| 到達目標區段 | 攻擊者如何接觸該 CAN?經 OBD、受入侵 ECU、外接設備,還是越過 Gateway? |
| 具有傳送能力 | 介面是否允許送出 Data Frame,而不是只有被動監聽? |
| 通訊參數相容 | 實體層、bit rate、Standard/Extended Format 與 CAN/CAN FD 是否正確? |
| 找到訊息語意 | 哪個 Identifier、DLC、Byte/Bit、Scaling 與狀態值會影響目標功能? |
| 符合時序條件 | 訊息是事件觸發還是週期傳送?接收端何時 timeout 或更新狀態? |
| 通過應用檢查 | Rolling Counter、Checksum、Freshness、狀態範圍與跨訊號關係是否合理? |
| 造成可觀察影響 | 接收 ECU 是否真的採用資料,最後影響顯示、功能或其他資產? |
在今天的 ICSim 裡,vcan0 提供同一個虛擬區段,cansend 提供傳送能力,ICSim Application 則依特定 ID 與 Data 更新模擬儀表。
這套環境刻意省略真實車輛中的 Gateway、ECU 狀態條件與應用層安全機制,目的只是讓我們觀察最小的 Injection 信任缺口。
這個問題不能只回答「攻擊者用更快頻率覆蓋」。
要先看兩筆 Frame 是否在同一個仲裁時刻開始。
這是今天實作的情況。
合法 Frame 先完成,注入 Frame 稍後取得 Bus,再成為另一筆獨立且格式正確的傳輸。
接收端可能依應用邏輯:
CAN Data Link Layer 不會替應用程式決定哪一筆語意比較可信。
若兩個節點送出相同的 Arbitration Field,它們不會在 Identifier 階段分出勝負。
如果後面的 Data 也完全相同,兩個節點可能一起完成這次傳輸。
如果 Data Field 出現不同 bit,某個傳送端可能送出 recessive 卻讀到 dominant,形成 bit error,接著出現 Error Frame 與重送。
所以不能把它描述成:
攻擊者在同一筆 Frame 傳到一半時,直接把合法 ECU 的 Data byte 換掉。
較精確的說法是,注入節點通常建立另一筆 Frame。
它可能排在合法訊息之前或之後,也可能因同時傳送不同內容而觸發錯誤處理。
高頻注入如何延遲其他訊息、錯誤事件如何影響可用性,會在 Day 20 的 DoS 與 Bus-Off 再討論。
假設 cansniffer 顯示某個 ID 在操作車門時有一個 bit 改變。
這只能建立一項候選關係:
使用者操作車門
→ 某個 Frame 的 Data 發生變化
還要用控制變因確認:
在真實系統中,還要排除 Rolling Counter、Application Checksum、Multiplexer 與多個 Signal 共用 Data Field 等情況。
所以逆向觀察得到的是待驗證的訊息假設,不是看到一個變動 byte 就取得完整 DBC。
| 資安屬性 | CAN Injection 情境 |
|---|---|
| 真實性 Authenticity | 接收端無法只靠 ID 確認真正發送者 |
| 完整性 Integrity | 應用程式取得了未授權節點建立的錯誤內容 |
| 新鮮度 Freshness | 若缺少 Counter 或時間檢查,舊狀態也可能被再次接受 |
| 可用性 Availability | 異常頻率、仲裁與錯誤處理可能延遲或阻斷其他通訊 |
| 機密性 Confidentiality | 單純注入不一定讀取祕密,但前置觀察可能暴露車況資料 |
Safety 仍然不是和 CIA 並列的資安屬性。
若錯誤資料進一步影響車輛功能或駕駛判斷,才可能形成 Safety 損害。
實際影響要看目標訊息、車輛狀態、接收端控制邏輯與其他防護,不能從一筆模擬儀表變化直接推論道路風險。
今天沿用 Day 07 已建立的環境:
SocketCAN → vcan0 → can-utils → ICSim/Controls
實作只在 vcan0 上進行。
我們不設定實體 can0,不連接 USB-CAN Adapter,也不使用道路車輛或他人的 OBD 接口。
| 項目 | 本篇設定 |
|---|---|
| 主線概念 | CAN Injection 與基礎 CAN 缺少 sender authentication |
| 隔離工具 | ICSim、SocketCAN vcan0 與 can-utils |
| 目標狀態 | ICSim 中的一扇模擬車門 |
| 攻擊動作 | 依觀察結果送出一筆單次錯誤狀態 Frame |
| 不做的事 | 不使用實體 CAN,不送循環流量,不重播整份紀錄,不測試真實 ECU |
| 輸出證據 | Seed、candump Log、候選 ID/Data、注入前後畫面與防護假設 |
vcan0先檢查介面與工具:
ip -details link show vcan0
command -v candump cansniffer cansend
vcan0 應顯示為 link/can 且介面已啟用。
今天所有傳送指令都明確寫死 vcan0。
如果介面不存在,回到 Day 07 的 Virtual CAN 建立步驟,不要把指令中的名稱改成道路車輛使用的實體介面。
在 Terminal 1 執行:
cd ~/ICSim
./builddir/icsim -r vcan0
ICSim 會顯示這次使用的 Seed,例如:
Using CAN interface vcan0
Seed: 1401717026
上面的數字只是官方文件中的格式示例。
實作時要記錄自己畫面上的實際 Seed。
在 Terminal 2 讓操作者輸入同一個 Seed,再啟動 Controls:
cd ~/ICSim
read -r -p "ICSim seed: " ICSIM_SEED
./builddir/controls -s "$ICSIM_SEED" -l 1 vcan0
ICSim 官方的 -r 會改變目標 Arbitration ID 與 Data byte 位置。
Controls 使用相同 -s Seed 才能和儀表同步。
-l 1 會加入 Padding,保留逆向觀察價值,又不讓未使用 byte 每次隨機改變。
保持兩個視窗運作,點一下 Controls 視窗確保它取得鍵盤焦點。
截圖位置 1:ICSim 與 Controls 使用相同 Seed 啟動
建議畫面包含 Terminal 的 Seed、模擬儀表與控制視窗
建議檔名:diagrams/day-19-icsim-randomized-seed.png
在 Terminal 3 建立本篇證據目錄並啟動 Log:
mkdir -p ~/can-labs/day19
cd ~/can-labs/day19
candump -tz -l vcan0
-l 會把 Frame 保存成 candump-日期_時間.log,-tz 則讓畫面使用從零開始的相對時間。
保持 Terminal 3 持續記錄。
在 Terminal 4 啟動差異觀察:
cansniffer -c vcan0
cansniffer 會強調 Data 內容的變化,適合從背景流量中找出與單一操作同步改變的候選 Frame。
先讓所有車門保持穩定,不操作油門與方向燈。
ICSim Controls 的鍵盤操作中,按住左側 Shift 再按 A 可以鎖定一扇門,按住右側 Shift 再按 A 則可解鎖同一扇門。
依下面順序重複三次:
鎖定 A 對應的車門
→ 等待畫面穩定
→ 記錄候選 ID 與完整 Data
解鎖同一扇門
→ 等待畫面穩定
→ 記錄同一 ID 的完整 Data
不要同時按方向鍵或油門,也不要一次切換多扇門。
你要找的是:
ICSim 的隨機化模式會讓每次 Seed 的 ID 與 byte 位置不同,所以本文不提供固定答案。
截圖位置 2:
cansniffer顯示候選 ID 與 Data 變化
建議畫面保留鎖定與解鎖各一組完整 Data
建議檔名:diagrams/day-19-door-signal-diff.png
找到候選 ID 後,在新的 Terminal 輸入實際觀察值:
read -r -p "Target 11-bit CAN ID (hex): " TARGET_CAN_ID
candump -tz "vcan0,${TARGET_CAN_ID}:7FF"
再次完成一次鎖定與解鎖,確認 Filter 後只留下目標 Frame,而且 Data 仍和剛才的觀察一致。
把兩個完整狀態記錄成:
| 狀態 | Identifier | DLC/Data 長度 | 完整 Data |
|---|---|---|---|
| 車門鎖定 | 實驗結果 | 實驗結果 | 實驗結果 |
| 車門解鎖 | 實驗結果 | 實驗結果 | 實驗結果 |
這張表是實驗紀錄模板,不是尚未完成的文章答案。
每位讀者都要填入自己 Seed 對應的實際結果。
先透過 Controls 把目標車門設定為鎖定,並確認 ICSim 畫面一致。
接著在 Terminal 5 輸入剛才觀察到的目標 ID,以及「車門解鎖」狀態的完整 Data:
read -r -p "Target 11-bit CAN ID (hex): " TARGET_CAN_ID
read -r -p "Observed unlocked data (hex only): " FORGED_CAN_DATA
cansend vcan0 "${TARGET_CAN_ID}#${FORGED_CAN_DATA}"
這個命令只送出一筆 Frame,不使用無限迴圈,也不持續提高 Message Rate。
預期觀察是:
Controls 仍保持原本操作狀態
→ vcan0 出現一筆相同 ID、不同 Data 的 Frame
→ ICSim 依收到的 Data 更新模擬車門顯示
完成後用 Controls 再次執行鎖定,將模擬畫面恢復到 Baseline。
如果畫面沒有變化,依序檢查:
TARGET_CAN_ID 是否為 11-bit 十六進位 ID不要用高頻迴圈補救未驗證的訊息假設。
先回到觀察與控制變因,找出失敗位於 ID、Data、時序還是應用語意。
截圖位置 3:單次注入前後的 ICSim 車門狀態
建議同時保留cansend命令與目標 ID 的candump紀錄
建議檔名:diagrams/day-19-single-injection-result.png
回到執行 candump -l 的 Terminal,按下 Ctrl+C。
確認 Log 已建立:
cd ~/can-labs/day19
ls -1t candump-*.log
最後整理下列證據:
| 證據 | 要回答的問題 |
|---|---|
| ICSim/Controls Seed | 這次隨機化訊息配置如何重現? |
| 鎖定與解鎖的完整 Frame | 哪個 ID、DLC 與 Data 變化和目標狀態相關? |
單次 cansend 指令 |
注入節點實際送出了哪一筆 Frame? |
| 注入前後畫面 | ICSim Application 是否採用該 Data? |
candump Log |
Baseline、合法操作、注入與恢復的時間順序為何? |
| 初步防護假設 | 哪一層可以拒絕不合理來源、頻率、狀態或新鮮度? |
完成後關閉 ICSim、Controls、cansniffer 與其他監聽程式。
重新開機時 vcan0 可能消失,這是 Virtual CAN 的正常行為。
安全與法律提醒:
cansend能對指定 SocketCAN 介面送出 Frame。本文所有命令都限定使用vcan0、ICSim、隔離測試台或明確取得授權的設備。不要把介面名稱改成道路車輛、他人的 OBD 介面或未授權網路,也不要在車輛行駛時進行測試。
如果單次注入讓 ICSim 車門狀態改變,我們可以合理確認:
vcan0 傳送 Frame 的能力candump 能留下合法操作與注入 Frame 的時間紀錄但這次實驗不能證明:
這個邊界非常重要。
ICSim 證明的是一個最小的信任問題:只依 Identifier 與 Data 採用內容時,另一個可傳送節點可以建立外觀相同的訊息。
它不是任何特定量產車的漏洞公告。
CAN Injection 的前提與接收路徑很長,防護也應放在多個控制點。

圖 2:降低 CAN Injection 風險需要限制入口、跨區資料流與訊息權限,再由接收端驗證及監控異常。任何單一控制都不應被當成完整防線
這一層降低攻擊者到達 CAN 的機會,但不能假設所有內部節點永遠可信。
Gateway 可以依 Ingress Network 與方向限制跨區傳輸,再檢查:
ID Allowlist 只能擋下未列入規則的訊息。
若受入侵節點位於允許傳送該 ID 的區段,仍需要後面的訊息與應用檢查。
AUTOSAR Secure Onboard Communication(SecOC,安全車內通訊)提供一種訊息保護架構。
SecOC 的 Authenticator 計算會結合 Data Identifier、受保護的 Authentic I-PDU 內容與完整 Freshness Value。
接收端再重建 Freshness 並驗證 Authenticator,協助偵測未授權修改與 Replay。
這裡要保留四個限制:
所以防護問題不是「有沒有一個 MAC byte」而已。
還要確認哪些資料受到保護、誰持有金鑰、驗證失敗如何處理,以及 Freshness 失同步後如何安全復原。
即使 Authenticator 驗證成功,持有合法金鑰但遭入侵的 ECU,或本身故障的訊號來源仍可能送出錯誤資料。
接收端可以依功能檢查:
密碼學驗證與 Plausibility Check 處理的是不同問題,兩者不能互相取代。
車內 IDS 可以建立正常行為 Baseline,觀察:
不過 IDS 看到異常,不等於一定能安全阻擋。
系統還要定義告警、限流、Gateway 規則更新、功能降級、事件保存與維修回應,並評估 False Positive 對可用性及 Safety 的影響。
Day 22 會再用 Identifier 頻率、週期、DLC 與內容合理性建立簡單偵測規則。
Day 18 的攻擊面清冊可以在今天往前推一步:
| 攻擊路徑階段 | 本篇證據 | 尚未證明的部分 |
|---|---|---|
| 到達 CAN 區段 | 測試程式可使用 vcan0 |
外部攻擊者如何進入真實車輛 |
| 取得傳送能力 | cansend 成功送出單一 Frame |
真實 Gateway 與介面是否允許 |
| 找到訊息語意 | 控制變因找出車門候選 ID/Data | 其他車款與版本是否相同 |
| 接收端採用 | ICSim 畫面依注入 Data 改變 | 真實 ECU 的應用檢查與致動結果 |
| 留下證據 | Seed、Log、畫面與恢復操作 | 量產系統的 Event Log 與來源追溯能力 |
| 可能損害 | 只觀察到模擬顯示狀態改變 | Safety、營運、財務或隱私損害 |
這張表說明了為什麼「我在 ICSim 用 cansend 改變一扇門」不能直接改寫成「我能遠端控制汽車」。
今天只確認攻擊路徑中間的一小段,前置入口、跨區權限、實際 ECU 行為與損害仍要另外用證據驗證。
cansend 可以驗證最小信任缺口,但不能證明特定量產車存在相同弱點今天送出的是一筆新建立的錯誤狀態 Frame,而且刻意限制為單次傳輸。
Day 20 將繼續分析 Replay、DoS 與 Bus-Off:舊訊息被重新送出時,接收端如何辨識?高頻流量如何影響仲裁與可用性?CAN 的 Error Counter 又會在什麼條件下讓節點進入 Bus-Off?