エグゼクティブ サマリー
サイバー攻撃に対して脆弱な産業用制御システム(ICS)の数が、日々増加しています。この膨大な数の重要な機器とネットワークの相互接続が進むにつれ、その運用を攻撃者が妨害する手段が増え、組織のネットワークを守る人々にとっては、攻撃ベクトルの可能性をすべてカバーするのがますます難しくなっています。これらの ICS がネットワークとどのように通信しているかを示すために、Talos は、3-D プリントで作成した石油採掘装置の模型をリリースし、2 つの産業用プロトコルをサポートするプログラマブル ロジック コントローラ(PLC)をシミュレーションしたものに接続しました。Talos では、年間を通じていくつかのワークショップでこの模型を紹介し、ワークショップ参加者が自分で実際に使えるようにしています。参加者の便宜を図るため、自宅でも試せるようにブループリントとコードも用意しています。
公開しているのは、採掘装置の 3-D プリント模型、Arduino ソース コード(Modbus over TCP プロトコルと EtherNet/IP プロトコルを含む)、ネットワーク経由でポンプを制御するためのヒューマン マシン インターフェイス(HMI)コードです。
現実の世界でこのデバイスの制御を攻撃者に握られてしまった場合、どれほど深刻な問題が起こり得るのかを示すために、モーターの速度が通常のペースを超えたときのポンプの反応を撮影した GIF 動画を用意しました。
ハードウェアの説明
グローバル アーキテクチャ
プロジェクトは、次の 7 つのパーツに分かれています。
- 3-D プリントされたパーツ。
- ポンプ。モーターによって制御されます。
- モーターの速度を示すゲージ。サーボ モーターで稼働します。
- Arduino UNO 基板。ポンプの頭脳部であり、PLC をシミュレーションしています。
- イーサネットをサポートするためのイーサネット Arduino シールド。
- モーターと発煙装置を管理するモーター シールド。
- Python と Flask フレームワークで開発した HMI。ポンプをリモートから監視および制御します。
次に、これらのコンポーネントをもう少し詳細に説明します。
石油採掘装置の 3-D オブジェクト
以下がポンプの模型です。
- オブジェクト 1 はポンプです。
- オブジェクト 2 はモーターで、ポンプを動かします。
- オブジェクト 3 には、3 つの基板が収められています。速度レベルを示すゲージも含まれています。
Talos の GitHub で .stl ファイルをダウンロードできます。
電子コンポーネント
システム コントローラとして機能する電子コンポーネントは、Arduino 基板(Arduino UNO)X 1、シールド X 2(イーサネットとモーター)、サーボ モーター X 1、モーター X 1、発煙装置 X 1 で構成されています。
Arduino UNO とイーサネット シールド(左側)は直接接続されています。VMA03 シールド(右側)を直接接続することも可能でしたが、今回のテストで、このコンポーネントから大きな電磁ノイズが発生することが確認されました。このノイズは、イーサネット信号に影響を与えます。そのため、2 つのシールドは分離することにしました。
Arduino とイーサネット シールドの電菱は USB ポートから供給します。VM03 シールドの電力は、12 ボルトのアダプタによって外部から供給します。
ソフトウェア
Arduino
Arduino ソース コードは、Talos の GitHub でダウンロードできます。ソースには 2 つのプロジェクトがあります。1 つ目のプロジェクトは Modbus over TCP プロトコルをサポートするもので、2 つ目は EtherNet/IP プロトコルをサポートします。それぞれのプロジェクトについて、Python スクリプトを使用して、通信、HMI、プロトコル スキャナ、または通信の PCAP をテストしました。
次に、Arduino の GPIO ピンについて説明します。
- モーター A(メイン ポンプ モーター)は、ピン 6(PWM)とピン 7(指示)によって制御されます。
- モーター B(発煙装置)は、ピン 9(PWM)とピン 12(指示)によって制御されます。
- ピン 8 は、速度ゲージによって使用されます。
- モーターの速度は、5,000 ~ 15,000 の範囲で任意の値を定義できます。デフォルトでは 8,000 に設定されています。ただし、速くしすぎるとポンプが壊れる可能性があるので注意が必要です。
- ポンプ コントローラの IP アドレスは、静的に10.10.1 に設定されています。これは setup() 関数で簡単に変更できます。
- Modbus over TCP プロトコルでは、速度はレジスタ 6 に設定されており、ゲージの値はレジスタ 7 に設定されています。レジスタとは、Modbus プロトコルにおける 16 ビットのオブジェクトです。
- Ethernet/IP プロトコルでは、速度は B1:1 に設定されており、ゲージは B1:7 に設定されています。Bx:y はタグで、Ethernet/IP で値を格納するために使用されています。
ポンプ作動中に、Arduino IDE のシリアル ポートを使用してデバッグすることができます。
実装したプロトコル
Modbus over TCP/IP
最初に実装したプロトコルは、Modbus プロトコルです。これは、1979 年に Modicon 社(現 Schneider Electric 社)によって実装されたプロトコルで、 TCP ネットワーク上で、コントローラとその他のシステムやデバイスとの通信に多く使用されています。Modbus について知りたい場合は、このページを読むことをお勧めします。今回の実装は、Mudbus ライブラリをベースにして行いました。次のコマンドがサポートされています。
- Read coil 0x01
- Read register 0x03
- Write coil 0x05
- Write register 0x06
- Write multiple coils, 0x0f
- Write multiple registers 0x10
- Get device information 0x43
コイル値は C[] アレイに格納され、レジスタ値は R[] に格納されます。ポンプは、レジスタのみを使用して、ポンプ モーターの速度とゲージの値を格納します。
PyModbus API を使用してデバイスを照会することができます。出力の例を次に示します。
from pymodbus.client.sync import ModbusTcpClient import sys client = ModbusTcpClient("10.10.10.1") result = client.read_holding_registers(6, 1) print(result.registers) result2 = client.read_holding_registers(7, 1) print(result2.registers) from pymodbus import mei_message rq = mei_message.ReadDeviceInformationRequest() result3=client.execute(rq) print(result3.information) client.close()
user@lab:~/pumpjack_project/arduino_modbus/python$ ./test.py [8000] [73] {0: 'Talos PLC', 1: 'pumpjack', 2: '0.1'}
EtherNet/IP
2 つ目のプロトコルとして、産業用インフラストラクチャで使用される EtherNet/IP を実装しました。これは、産業用共通プロトコル(CIP)をイーサネットに適用したプロトコルです。今回このプロトコルを完全には実装しておらず、read タグと write タグのみサポートしています。Talos では、Micrologix または SLC PLC のプロトコルをサポートしています。このプロトコルは、Modbus プロトコルに非常に似ていますが、セッション ID の概念も含んでいます。今回の実装ではセッションが含まれています。
現在のバージョンでは、Bx:x タグと Nx:x タグがサポートされています。x は 0 ~ 9 の数字を表します。
pycomm API を使用して、デバイスを照会することができます。以下に例を示します。
from pycomm.ab_comm.slc import Driver as SlcDriver import logging c = SlcDriver() def read_val(num): print c.read_tag('B1:%d' % num)[3] if c.open('10.10.10.1'): read_val(1)
user@lab:~/pumpjack_project/arduino_ENIPCIP/python$ ./test.py 8000
ヒューマン マシン インターフェイス(HMI)
最後に、ポンプを管理する HMI を実装します。HMI は、ポンプと通信する Web サーバと PyModbus を作成するために、Flask を使用して Python で開発しています。以下に、インターフェイスのスクリーンショットを示します。
Web サーバは最初に、「get device information」(0x43)コマンドを使用して、Modbus over TCP プロトコルでポンプ デバイスの名前とバージョンを取得します。次に、モーター速度とゲージの値を取得します。この値によって、Web ページでのゲージ レベルが決まります。加速ボタンまたは減速ボタンをクリックすると、Modbus プロトコルによってモーターの速度が加速または減速し、レジスタ 6 の値が変更されます。
ワーク ショップの例
研究者は、さまざまな方法でこのシステムを利用し、石油採掘装置への攻撃ベクトルを調査することができます。たとえば、このシステムを使用して、2 つの ICS プロトコルについて理解することができます。これらのプロトコルは、従来の IT ネットワークでは利用することのないものです。HMI にネットワーク トラフィックのパケット キャプチャ機能を作成し、Wireshark でさらに分析することができます。Wireshark 解析ツールを組み込むことで、Modbus over TCP を完全に解析することができます。EtherNet/IP プロトコル解析ツールは、機能面では劣りますが、手動で部分的にデコードすることができます。これはとてもよい演習になります。Cisco Talos の Jared Rittle が以前に Wireshark 解析ツールで解析した結果の一部を、こちらから参照できます。
もう 1 つのシナリオは、ローカル ネットワークをスキャンして Modbus システムを特定し、コイルとレジスタに格納されている値を取得して変更することで、ポンプの動作を変えるというものです。Stuxnet(SCADA システムを攻撃する悪意のあるワーム)などの ICS 攻撃に関心がある方は、HMI システムを侵害して、HMI からオペレータに提供される情報を変更した場合の影響を確かめることができます。
これらはすべて攻撃側のシナリオです。防御側のシナリオを実施することをお勧めします。たとえば、SNORTR では Modbus over TCP がサポートされています。詳細はこちらで確認できます。このモジュールでは、トラフィックの監視、不正な IP アドレスからの要求のブロック、大規模なスキャンの特定、レジスタ/コイルの上限値制御などを実施し、採掘装置の破損を回避することができます。
まとめ
研究者にとってこれらの資料が、産業用プロトコル、特に Modbus over TCP や EtherNet/IP の理解を深めるために役立てば幸いです。これら 2 つのプロトコルは、実稼働環境で常に使用されている未認証のプロトコルです。この記事で挙げた例では、PLC(Arduino UNO によってシミュレーション)の内部の値を変更する方法を確認しました。しかし、今回のプロトコルでも PLC をプログラミングすることができます。実際の PLC では、同じプロトコルを使用して PLC をプログラミングしたり、元のコードを置き換えたりすることができます。また、パッチを適用することも可能です。実際の PLC 攻撃に関する詳細については、こちらに掲載されている Talos のホワイト ペーパー『Process Control through counterfeit comms: Using and abusing built-in functionality to own a PLC』[英語] を参照してください。
Talos では、できるだけ多くの対象者に利用していただけるように、このプロジェクトを公開することにしました。実装されたプロトコルに機能を追加したり、新しいプロトコルを追加したりするなど、自由にこのプロジェクトに参加してください。Talos の GitHub でのプル リクエストにも、喜んで対応します。
本稿は 2019年2月11日に Talos Group のブログに投稿された「What you can learn from Cisco Talos’ new oil pumpjack workshop」の抄訳です。