今回のブログでは、PLC 感染のプロセスと、PLC 感染の検出方法について詳しい続報をお届けします。
はじめに思い出していただきたいのは、Stuxnet は特定の種類の SIMATIC PLC が感染することを最終目標にしています。この目標を達成するために、SIMATIC DLL が置き換えられ、プログラミング環境と PCL デバイスの間でプロキシとして動作します。この DLL には、次の機能があります。
- PLC とプログラミング環境の間の通信を監視する
- PLC を感染させる
- 潜在的な PLC 感染を隠す
シーケンスは悪質なブロックと、すでに存在する PLC ブロックの感染スタブで構成されます。Stuxnet のシーケンスには 2 つのタイプがあります。
シーケンス A および B
1 つ目のタイプには、シーケンス A および B があります。各シーケンスはおよそ 20 のブロックで構成され、特定のシステムデータブロックを持つことで PLC 315-2 だけを標的とします。詳しくは、調査詳細のホワイトペーパーを参照してください。シーケンス A および B は PROFIBUS フレームの監視を目的とし、さらには細工したフレームを PROFIBUS ネットワークに挿入します。
このシーケンスの構成は以下のとおりです。
- 静的ブロック
- DB888 から DB891
- FC1865 から FC1868、FC1870、FC1871、FC1873、FC1874、FC1876 から 1880
- 悪質な DP_RECV ブロック
- 動的ブロック
- 感染ブロック
図 1: シーケンス A および B のフローチャート
PLC がシーケンス A または B によって感染しているかどうかを簡単に判定するには、未感染の環境で SIMATIC Manager を起動し、ブロック OB1 と OB35 を調べます。感染した OB1 は以下の命令で始まり、感染シーケンスを開始して、特定の条件が満たされれば OB1 の実行を短絡しようとします。
UC FC1865
POP
L DW#16#DEADF007
==D
BEC
L DW#16#0
L DW#16#0
感染した OB35 は以下の命令で始まり、特定の条件が満たされれば OB35 の実行を短絡しようとします。
UC FC1874
POP
L DW#16#DEADF007
==D
BEC
L DW#16#0
L DW#16#0
シーケンス C
2 つ目のタイプのシーケンス C は Stuxnet のどちらの亜種にも存在しますが、PLC には書き込まれないことが解析で明らかになっています。これは、重要なコード中で発生する例外が原因です。
コードが未完成であるため、あるいは部分的にコメントアウトされているため、元のコードの大半はそのままで、呼び出されない状態になっています。標的はタイプ 417 の PLC であり、メモリにマップされた PLC の I/O(入力/出力)領域や周辺機器の I/O に対して、I/O 情報の読み取りと書き込みを試みようとします。
このシーケンスの構成は以下のとおりです。
- 静的ブロック
- DB8062、DB8063
- FC6055 から FC6084
- OB80(存在しない場合)
- 動的ブロック
- 感染ブロック
図 2: シーケンス C のフローチャート
シーケンス A および B では独立したスレッドで感染が制御されますが、シーケンス C の感染は、s7blk_write() の API 呼び出しを介してタイプ OB、DB、FC、FB のブロックが PLC に書き込まれるときにトリガされます。
DB8061 は既存の SDB7 に基づいて生成され、SDB7 は Stuxnet によって標的の PLC 上で検出されると想定されているようですが、コードが未完成あるいは部分的に削除されているようであり、詳しいことは解明されていません。このことから、タイミングエラーハンドラである OB80 の使われ方が偶然に判明するかもしれません。シーケンス C は、期待した結果に至らないことがあるため、無効化されたと考えられます。この仮説が正しいとしても、シーケンス C がコードに残されている理由は不明です。
SDB0 は、レコードを含むと想定されています。このブロックが解析されると、長さ 10 バイトの静的なレコードがブロックに挿入されますが、シーケンス A および B のプロセスとは異なり、ブロックで特定の値は検索されません。さらに、SDB0 のレコード 13 は修正が可能です。
SDB0 の作成を示すタイムスタンプが増分され、一貫性を保つためにこのタイムスタンプは SDB4 の特定の位置に複製されます。シーケンス C が書き込まれ、Stuxnet は OB80 が存在することを確認して、存在しない場合には空のブロックを作成します。
さて、技術的な説明は別にしても、フィンガープリントのチェックがほとんど行われていないことに注目してください。これは厄介です。シーケンス A および B は、特定の定数を検索して SDB ブロックを重点的にチェックするのに対し、シーケンス C は SDB0、SDB4、SDB7 の存在を確認する以外、ほとんどチェックなしに書き込まれます。ただし、前述したように、このシーケンスを管理するコードは無効化されているようです。
最悪のシナリオとして、PLC がシーケンス C で感染した場合、OB1 ブロックは以下の命令で開始されます。
UC FC6083
Windows コンポーネントに対する Stuxnet の検出とその修復は信頼性が高く、すでに数か月の実績がありますが、感染した PLC の検出とクリーニングには追加の手順が必要です。まず、Stuxnet の Windows バイナリを削除する必要があります。そうすれば、PLC で以下の Stuxnet ペイロードの主な要素について調べることができます。
- シーケンス A と B の標的は、タイプ 315-2 の PLC だけです。このタイプでは、OB1 と OB35 が感染します。
- シーケンス C の標的は、タイプ 417 の PLC だけです。このタイプでは、OB1 が感染しますが、このシーケンスは無効化されているようです。