マイコンの重要なデータは通常、データの読み出しを制限する「読み出し保護機能」によって守られていますが、その機能の回避方法はセキュリティ研究者などによって日々研究開発されています。組み込みエンジニアのMarc Schink氏とJohannes Obermaier氏は、マイコンの1つであるSTM32F1シリーズの保護機能を回避する方法をブログで公開しています。

Exception(al) Failure - Breaking the STM32F1 Read-Out Protection | blog.zapb.de

https://blog.zapb.de/stm32f1-exceptional-failure/

STM32F1シリーズでは、攻撃者は物理的なアクセスが可能であればデバッグ機能を使用することが可能。また、プログラムに例外が発生した際、プロセッサはベクタテーブル上に示された例外処理のアドレスも同時にプログラムカウンタ(PC)に読み出しますが、この読み出しを可能にするため、STM32F1シリーズの読み出し保護機能はDCodeバスのみを対象とており、ICodeバスからのメモリアクセスをブロックしません。ICodeバスの処理を利用すれば、読み出し保護された情報を読み出せることになります。

「ベクタテーブルに例外を追加する」方法が一般的な脆弱性を突く方法だそうですが、STM32F1シリーズではベクタテーブルに空きがないため、この方法は使えないとのこと。



「ベクタテーブルに例外を追加する」方法の代替案が「ベクタテーブルのオフセットを利用する」方法です。攻撃者はデバッグ状態に入ることが可能なので、STM32F1シリーズのCPU「ARMv7-M」に搭載されている「ベクタテーブルオフセット登録機能(VTOR)」を利用して、ベクタテーブルを置き換えることができます。

ベクタテーブルの中でも図の赤色で示された特殊な例外や予約済みのデータについては、VTORによる置き換えでもデータを抽出できませんが、この制限は「ベクタテーブルのサイズ以上の例外番号で例外の置き換えを行う」ことで回避できるとのこと。今回はテーブルのサイズが32なので、32以上の例外番号を用いて例外を置き換えれば、ベクタテーブルのすべての例外でデータの抽出を行うことができます。



例外を発生させる方法も説明されています。まずはOpenOCDのコマンドを用いて、例外の発生を抑止する割り込みマスクを無効にしておく必要があります。

cortex_m maskisr off


例外の1つである「BusFault」例外を発生させデータを抽出するには、STM32F1シリーズでは未割り当てのメモリ空間「0xf0000000」を実行させます。するとBusFaultが発生し、PCに例外処理のアドレスが保存されます。

mwh 0x20000000 0x0868
reg r1 0xf0000000
reg pc 0x20000000


実行禁止のメモリ領域を実行しようとした時などに発生する「MemManage」例外も、以下のコマンドを実行すれば発生させることができます。

reg pc 0xe0000000


この脆弱性を使ってSTM32F1シリーズを攻撃するテストを行ったところ、フラッシュメモリ内のおよそ90%に及ぶデータを抽出できたとのこと。Marc氏とJohannes氏は「STM32F1シリーズの読み出し保護機能は突破された」と結論づけており、機能を利用するのを避けるべきだと主張しています。



なお、実際にSTM32F1シリーズをハックしているムービーも公開されています。

ムービー中で使用されているスクリプトは、下記から確認することができます。

zapb / stm32f1-firmware-extractor · GitLab

https://gitlab.zapb.de/zapb/stm32f1-firmware-extractor