Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deep Dive into RAMN CTF

Avatar for ishii ishii
July 25, 2025
300

Deep Dive into RAMN CTF

Avatar for ishii

ishii

July 25, 2025
Tweet

Transcript

  1. RAMNとは? (Resistant Automotive Miniature Network) • トヨタ自動車が開発したオープンソースの車載ECUテストベッド • 特徴: •

    小型・低コストでリアルな車載ネットワークを模擬 • CTF (Capture The Flag)にも活用 • 主要機能: • CAN / CAN-FD ネットワークシミュレーション • 実車の通信環境(UDS診断など)を再現 3
  2. RAMNのシステム構成: 4ECU • ECU A (Master): • PCとUSB接続(電源供給・slcanゲートウェイ) • ECU

    B, C, D (Nodes): • CAN-FDバスで相互通信 4 ECU A: スクリーン ECU B: ステアリングホイール ハンドブレーキ ECU D: エンジンキー 各種ライト ECU C: アクセル, ブレーキ シフトレバー
  3. ハードウェア詳細 • ハードウェア • STM32L5マイコン(ARM Cortex-M33) • TrustZoneセキュリティ機能 • 256KB/512KB

    Flash • FreeRTOS搭載 • 通信・デバッグ I/F: • CAN/CAN-FD • USB (Type-C): • 電源供給 • slcanプロトコル (PCツールとの連携) • JTAG / SWD: • ハードウェアデバッグ用ポート 5
  4. RAMNを使用した過去のCTF • DEFCON Car Hacking Village • Automotive CTF Japan

    2024 • Block Harbor VicOne Automotive CTF 2024 など • 過去問のFirmwareはGithubで公開 • RAMNを購入すれば手元で再現可能 ※ RAMNはPCBWayから購入できます 6
  5. 過去問題の傾向分析 ~カテゴリ別出題数~ • Firmwareをリバース CAN/UDSでメッセージ送信 FLAG 取得が王道 カテゴリ 問題数 主な解法・攻撃手法

    CAN 8 メッセージ送信, CRC解析, UDS 9 SID (0x22, 0x27等) を利用した情報窃取,隠しサービスの探索 Hardware 8 マイコンの仕様情報を利用, JTAG/UART/I2C 通信 Reverse 5 ファームウェア (ELF/HEX) の静的解析 Forensics, USB, etc. - USBプロトコル解析(RAMN specific) ステガノグラフィ (LSB, タイミング) 7 ※ 1問に複数カテゴリが該当することもあり、全体の問題数は28問程
  6. 紹介する問題 • Block Harbor VicOne Automotive CTF 2024 • Title:

    [A/C] Ramen Clicker • Tags: CAN, Hardware • Title: [D] Forgotten Field • Tags: CAN, Hardware • Title: [C] DID not done • Tags: UDS • Title: [D] Security Access 1 • Tags: Reverse, UDS, Hardware 8 ※ [A~D]は対応するECUを表します。
  7. 1問目:[A/C] Ramen Clicker • Tags: CAN, Hardware • Intended difficulty:

    Medium/Difficult • Description: • My high score is 0x9000. 9 ECU Aに給電するとラーメン の画面が出力されます ECU C: シフトレバー
  8. 1問目:[A/C] Ramen Clicker 初動調査 - 動作を眺める • 現象 • ECU

    Cのレバーを押すとECU Aでカウントアップされる • 考察 • ECU CからECU Aにデータが送られているはず! • ECU間はCANバスでつながっている • とりあえずCAN通信を眺める • ECU AのCAN RXモニター 10 ECU C: シフトレバー
  9. 1問目:[A/C] Ramen Clicker 初動調査 - クリック時の動作を調査 • シフトレバーをクリックしたときを観察 • 攻撃の方針を考える

    • 045#00 01 ⇔ 00 06 を交互に送信したらECU Aのカウントを騙せそう 11 CAN ID: 045で 00 01⇔00 06 が切り替わる
  10. 1問目:[A/C] Ramen Clicker クリック時のメッセージを偽装 • USB接続したPCからCANメッセージを送信 • ECU Aの液晶に以下が表示される 12

    $ sudo slcand -o -c /dev/ttyACM0 && sudo ip link set up can0 $ cansend can0 045#0006 #シフトレバーを押したときに流れるメッセージ 正規のCANメッセージ でないことがバレている
  11. 1問目:[A/C] Ramen Clicker 考察:なぜチートがばれたのか • CANの概要 • ブロードキャスト型のプロトコル • 全てのノードが全てのメッセージを受信

    • CANフレームには送信元アドレスの情報はない なりすまし可能 • 送信したCANメッセージ • CAN BUSに流れるフレームはECU Cが出すものと全く同一 原理的にECU Aはチートを検出できない 13 $ cansend can0 045#0006 なぜバレた?
  12. 1問目:[A/C] Ramen Clicker 考察:なぜチートがばれたのか • あるECUだけ攻撃者が送信したメッセージが偽物だとわかる • 誰か:ECU C •

    なぜか:ECU C は CAN ID:045を受信するはずがないから • 考えられたチート検出の流れ 14 ECU A ECU C 攻撃者 1. 045#00 06 を送信 2. 045#00 06 を受信 3. チートを知らせる メッセージを送信 3. チートを検出!
  13. • ECU Aに対してECU Cに給電を止めるコマンドを送信 16 1問目:[A/C] Ramen Clicker ECU Cを停止する

    $ picocom -&imap crcrlf -&echo /dev/ttyACM12 -b 115200 picocom v3.1 … Type [C-a] [C-h] to see available commands Terminal ready yC0 ECU Cを止めるとチート が検出される! 考察 ECU Cからの定期送信が消えるとチート 判定になるのではないか?
  14. 17 1問目:[A/C] Ramen Clicker ECU Cの定期送信を取得 ECU Cが止まっているとき ECU Cの

    定期送信 ECU Cが生きているとき $timeout 10s candump –L can0 | grep -Ev '016#|157#|213#|442#|607#' > candump.log
  15. • Step1. ECU Cを模倣 • Step2. ECU Cを停止 • Step3.

    クリック時のメッセージを送信 18 1問目:[A/C] Ramen Clicker ECU Cを再現してクリックを高速で実行 while true; do cat candump.log | canplayer can1=can0; done while true; do cansend can1 045#0006; sleep 0.0001; cansend can1 045#0001; sleep 0.0001; done
  16. • Step1. ECU Cを模倣 • Step2. ECU Cを停止 • Step3.

    クリック時のメッセージを送信 19 1問目:[A/C] Ramen Clicker ECU Cを再現してクリックを高速で実行 while true; do cansend can1 045#0006; sleep 0.0001; cansend can1 045#0001; sleep 0.0001; done 高速でカウントアップ し、FLAGゲット! while true; do cat candump.log | canplayer can1=can0; done
  17. 2問目: [D] Forgotten Field • Tags: CAN, Hardware • Intended

    difficulty: Medium/Difficult • Description: • Many tools consider a CAN frame consists of arbitration ID, control flags, and data fields. ID 0x607 thinks they should check some more. • 多くのツールでは、CANフレームはアービトレーションID、コントロールフラグ、 およびデータフィールドで構成されると考えられています。ID 0x607は、もっと他 にもチェックすべきことがあると考えているようです。 20
  18. • CRC Fieldになにかありそうというのが第一感 • CRC:Cyclic Redundancy Check:巡回冗長検査 • エラー検出に使われる 22

    https://i0.wp.com/piembsystech.com/wp-content/uploads/2024/08/CAN- Protocol-Standard-Frame-Format.jpg 2問目:[D] Forgotten Field CAN 標準フォーマットのフレーム構造 • Many tools consider a CAN frame consists of arbitration ID, control flags, and data fields. 上記以外のフィー ルドに何かありそう
  19. • CANは高い信頼性が求められるシステムで広く使われている • ブレーキ、エンジン制御、エアバッグなど • CRC Field(エラー検出)がないと以下のようなシナリオが考えられる • 自動ブレーキシステムが前方車両との接近を検出 •

    ブレーキECUに80%でブレーキをかけるようにCANメッセージを送信 • CANバス上でノイズにより80%という値が10%に化ける • ブレーキECUが10%でブレーキをかける • 減速が足りず事故発生 23 2問目:[D] Forgotten Field 少し脱線:なぜCRC Fieldがあるのか CRCがあるとフレームの 伝送誤りを検出可能!
  20. • CRC : 入力bit列を除数(生成多項式)で割った余り • 入力: • SOF: 0 •

    ID: 0x607 • RTR: 0 • データフレームの場合は0 • IDE: 0 • 標準フォーマットの場合は0 • R(予約ビット): 0 • DLC: 3 • Data Field: 0x626718 24 2問目:[D] Forgotten Field CRC-15-CAN CRC : 0x0062 -> ‘b’ 入力
  21. • CRCを計算するcandumpのラッパーを実装 25 2問目:[D] Forgotten Field CRC-15-CANの計算 CRCをasciiとして読むと bh{LAGGING_BEHIND} POLY

    = 0x4599 # CRC-15-CANの多項式 for bit in bits_to_process: do_xor = (crc_reg >& 14) & 1 crc_reg <&= 1 if do_xor ^ bit: crc_reg ^& POLY
  22. 3問目:[C] DID not done • Tags: UDS • Intended difficulty:

    Medium/Difficult • Description: • Flag is a 26-byte string at 0x0803e000 but Read Memory By Address won't let me read it :( • 診断通信であるUDS の Read Memory By Address で 0x0803e000の中身を 読み取れば良さそう 26
  23. • CaringCaribouを用いてUDSサービスを調査 • オープンソースの車載セキュリティ調査ツール $ caringcaribou uds services 0x7e2 0x7ea

    ------------------- CARING CARIBOU v0.7 - python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] ------------------- Loading module 'uds'Probing service 0xff (255/255): found 8Done! Supported service 0x10: DIAGNOSTIC_SESSION_CONTROL Supported service 0x11: ECU_RESET Supported service 0x22: READ_DATA_BY_IDENTIFIER Supported service 0x23: READ_MEMORY_BY_ADDRESS Supported service 0x27: SECURITY_ACCESS Supported service 0x2c: DYNAMICALLY_DEFINE_DATA_IDENTIFIER Supported service 0x2e: WRITE_DATA_BY_IDENTIFIER Supported service 0x3e: TESTER_PRESENT 27 3問目:[C] DID not done UDSサービスの調査
  24. • Read Memory By Address をしてみる 28 3問目:[C] DID not

    done UDSサービスの調査 $ echo "23 24 08 03 e0 00 00 02" | isotpsend -s 7e2 -d 7ea can0 Read Memory By Addressはどのセッションで実行しても失敗する
  25. • DYNAMICALLY_DEFINE_DATA_IDENTIFIER これが初見 • DIDを動的に設定することができるサービス Dynamically Define Data Identifier (0x2C)

    Service in UDS Protocol - PiEmbSysTech 29 Supported service 0x10: DIAGNOSTIC_SESSION_CONTROL Supported service 0x11: ECU_RESET Supported service 0x22: READ_DATA_BY_IDENTIFIER Supported service 0x23: READ_MEMORY_BY_ADDRESS Supported service 0x27: SECURITY_ACCESS Supported service 0x2c: DYNAMICALLY_DEFINE_DATA_IDENTIFIER Supported service 0x2e: WRITE_DATA_BY_IDENTIFIER Supported service 0x3e: TESTER_PRESENT 3問目:[C] DID not done UDSサービスの調査 これを使えば、メモリアドレス を参照するDIDを設定できそう Read DIDで中身を出力
  26. • Gemini sanに聞いてみる ➢ UDSのサービスである 0x2c: DYNAMICALLY_DEFINE_DATA_IDENTIFIER の Subfunction 0x02

    の使 い方を教えてください。 ステップ1: 動的DIDの定義 (0x2C と 0x02 を使用) まず、読み出したいメモリアドレスを動的DIDとしてECUに定義させます。 シナリオ: メモリアドレス 0x2000A000 から 4 バイトのデータを、新しい動的DID 0xF200 として定義す る。 リクエストメッセージ: [2C] [02] [F2 00] [44] [20 00 A0 00] [00 00 00 04] | | | | | | | | | | | +-& 読み出す長さ (4バイト) | | | | +--------------- 開始メモリアドレス (0x2000A000) | | | +------------------------- アドレスと長さのフォーマット (※1) | | +------------------------------- 定義する動的DID (0xF200) | +-------------------------------------- サブファンクション: defineByMemoryAddress +------------------------------------------- サービスID: DDDI 30 3問目:[C] DID not done DYNAMICALLY_DEFINE_DATA_IDENTIFIER のフォーマットの調査
  27. • Step1 : DDDI(DYNAMICALLY_DEFINE_DATA_IDENTIFIER)の設定 [2C] [02] [F2 00] [44] [08

    03 E0 00] [00 00 00 1A] | | | | | | | | | | | +-& 読み出す長さ (4バイト) | | | | +--------------- 開始メモリアドレス (0x0803e000) | | | +------------------------- アドレスと長さのフォーマット | | +------------------------------- 定義する動的DID (0xF200) | +-------------------------------------- サブファンクション: defineByMemoryAddress +------------------------------------------- サービスID: DDDI • Step2: Read DIDで中身を出力 31 3問目:[C] DID not done READ DIDでFLAGの取得 Flag ゲット!
  28. [2C] [02] [F2 00] [44] [20 00 A0 00] [00

    00 00 04] | | | | | | | | | | | +-& 読み出す長さ (4バイト) | | | | +--------------- 開始メモリアドレス (0x2000A000) | | | +------------------------- アドレスと長さのフォーマット (※1) | | +------------------------------- 定義する動的DID (0xF200) | +-------------------------------------- サブファンクション: defineByMemoryAddress +------------------------------------------- サービスID: DDDI (※1) addressAndLengthFormatIdentifier (1バイト): 上位4ビットがメモリアドレスのバイト 数、下位4ビットが長さのバイト数を示します。この例の 0x44 は「アドレス4バイト、長さ4バイト」を 意味します 32 3問目:[C] DID not done 補足: 生成AIは嘘を付くのでご注意 これは嘘でした 上位4ビットが長さのバイト数で、下位4ビットがメモリアドレスのバイト数 [44] [20 00 A0 00] [00 00 00 04]
  29. 4問目:[D] Security Access 1 • Tags: Reverse, UDS, Hardware •

    Attachment: ECUD.hex (flags are redacted) • Intended difficulty: Very Difficult • Description: • The attached file corresponds to the firmware of ECU D, with all its flags redacted. Try to extract the real value of bh{XXXXXXXXXXXXXXXXXXX} from your RAMN hardware. • 添付ファイルは、すべてのフラグが編集・削除されたECU Dのファームウェアです。あなた のRAMNハードウェアから、bh{XXXXXXXXXXXXXXXXXXX}の実際の値を抽出してください。 33
  30. • UDS の0x22(Read Data by Identifier)の処理っぽい • 前後の処理に0x27(Security Access)などもあったため 35

    4問目:[D] Security Access 1 FirmwareをGhidraで解析 – Flagの取得方法を特定 UDSでRead DIDしてみる が、 SecurityAccessDenied
  31. • ネガティブレスポンスを設定している処理を探す • 0x33: securityAccessDenied 36 *DAT_08002300 が 1 以外の

    時はsecurityAccessDeniedを 返す これを1に出来ればFLAGゲット! 4問目:[D] Security Access 1 FirmwareをGhidraで解析 – Flagに必要な条件を特定
  32. 38 4問目:[D] Security Access 1 FirmwareをGhidraで解析 – AIに関数を聞いてみる ➢ Q:FUN_0800be24

    は何をしている ➢ 関数ですか? 今回はGhidraMCP で試してみた ChatGPTなどには デコンパイル結果を 貼り付ければOK
  33. • memcmp(param_2 + 2,DAT_08002310,0x10); • param_2: [27 02 key0 …

    key15] • DAT_0800231: 0BF974C0h • 0BF974C0h • これはどこのアドレス空間? 39 4問目:[D] Security Access 1 memcmpされるバッファを特定
  34. • 0BF974C0h • これはどこのアドレス空間? • Flash System Memory • ブートローダー

    • パッケージ固有情報 • TrustZone関連の設定 • など • あまり情報がい • おそらくブートローダー 40 4問目:[D] Security Access 1 STM32L5ファミリのReference Manualを調査 STM32L5の Reference Manual
  35. • ECU DでSystem Memoryを見ることはできなさそう • System Memoryだから、パッケージ固有情報な値以外であれば 別のECUから取得した値でもよさそう 前の問題を思い出すと。。。 •

    Title: [C] DID not done • やったこと:DDDIでDIDを設定、Read DID経由でメモリの中身を取得 41 4問目:[D] Security Access 1 STM32L5ファミリのReference Manualを調査 これは使える!
  36. 42 4問目:[D] Security Access 1 ECU Cの 0x0BF974C0 から16バイト読み出してみる •

    Step1 : DDDIの設定 [2C] [02] [F2 00] [44] [0b f9 74 c0] [00 00 00 10] | | | | | | | | | | | +-& 読み出す長さ (4バイト) | | | | +--------------- 開始メモリアドレス (0x0BF974C0) | | | +------------------------- アドレスと長さのフォーマット | | +------------------------------- 定義する動的DID (0xF200) | +-------------------------------------- サブファンクション: defineByMemoryAddress +------------------------------------------- サービスID: DDDI • Step2: Read DIDで中身を出力 “@Internal Flash ” これがKEY!
  37. • 今年のCHVCTFのために勉強をかねてRAMN CTFの紹介をしました • Block Harbor VicOne Automotive CTF 2024

    • Title: [A/C] Ramen Clicker • Tags: CAN, Hardware • Title: [D] Forgotten Field • Tags: CAN, Hardware • Title: [C] DID not done • Tags: UDS • Title: [D] Security Access 1 • Tags: Reverse, UDS, Hardware 44 おわりに CAN プロトコルの理解が必要! Reverseは生成AIを活用することで 比較的とっつきやすくなった