こんにちは!新人ITエンジニアや、これからセキュリティの勉強をはじめる開発者の皆さん、日々の業務お疲れ様です。「セキュリティ」と言聞くと、なんだか難解な暗号や、映画に出てくるようなハッカーの黒い画面を想像して身構えてしまいますよね。
でも大丈夫です!一歩ずつ、身近な例えから紐解いていけば、セキュリティの本質はとってもシンプルです。今回は、工場やインフラを裏で支える「産業用制御システム(SCADA)」と、そこで使われている歴史ある通信ルール「Modbus TCP」のセキュリティについて、一緒に優しく学んでいきましょう!
—
1. 家の鍵のない「共有アパート」?Modbus TCPの正体
まずは、私たちが普段暮らしている「おうちの防犯」に例えて考えてみましょう。
皆さんの自宅の玄関には、しっかりとした鍵がついていますよね。「おかえりなさい」とドアを開けるとき、合鍵やスマートロックを使って、本人であることを確認してから家に入ります。これが「認証」という仕組みです。
ところが、工場やビル空調の制御で使われるModbus TCPという通信プロトコルは、いわば「鍵のついていない、誰でも自由に出入りできるシェアハウスの共有リビング」のようなものなんです。
昭和の時代に作られた設計のまま今に至る
Modbusは1979年に生まれた、とても歴史のある通信規格です。当時は、工場の中は外の世界から完全に切り離された「閉じた世界(ローカルネットワーク)」でした。「誰も悪さをする人はいないだろう」という性善説で作られたため、「誰が命令を送ってきたか(発信者の身元)」を確認する機能(認証)が、最初から備わっていないのです。
時代が進み、IoTの波に乗って、こうした工場設備がインターネットと繋がるようになりました。するとどうでしょう。「鍵のついていない家」に、世界中から誰でもアクセスできるようになってしまったのです。これが、現代のOT(制御システム)セキュリティにおける最大の悩みのタネなんです。
—
2. 攻撃者はどうやって忍び込み、何を企むのか?
もし、泥棒が「鍵のついていない家(Modbus TCP)」を見つけたらどうなるでしょうか? 侵入した泥棒は、部屋の中にある家電のリモコンを勝手に操作し放題になってしまいます。
これをサイバーの世界に置き換えてみましょう。Modbus TCPは、主にTCPポートの 502 番を使って通信します。攻撃者はインターネット経由でこの 502 番ポートスキャンを見つけ出すと、次のような悪質なコマンドを送りつけてきます。
- 不正なレジスタ操作: 水道局の流量計のデータを書き換えて、水圧を異常値に設定する。
- コマンドインジェクション(停止命令): 発電所のタービンを緊急停止させるレジスタ(メモリの番地)に直接「停止」の値を書き込み、設備を強制終了させる。
物理的な破壊や社会インフラの麻痺に直結するため、非常にスリリングで恐ろしい攻撃手法ですが、メカニズム自体は「宛先を指定してデータを書き換える」という非常に単純な仕組みで行われています。
—
3. Pythonで覗いてみるModbusの世界
百聞は一見にしかず。実際にModbusの通信がどれほどシンプルなものか、Pythonのライブラリ(pymodbusなど)を使った簡単なサンプルコードで覗いてみましょう。
以下のコードは、工場にある機器(PLCなど)のIPアドレスを指定して、温度センサーのデータを読み取るスクリプトの例です。
from pymodbus.client import ModbusTcpClient
# 制御対象の機器(PLC)のIPアドレスとポート番号を指定します
# 例えるなら「訪問先の家の住所とインターホンの場所」です
target_ip = "192.168.1.100"
target_port = 502
# Modbus TCPクライアントを初期化します
client = ModbusTcpClient(target_ip, port=target_port)
try:
# 接続を試みます
connection = client.connect()
if connection:
print(f"[+] {target_ip}:{target_port} への接続に成功しました!")
# レジスタのアドレス 0 番地から、センサーの温度データ(1ワード分)を読み取ります
# ※Modbusには認証がないため、アドレスさえ分かれば誰でもこの命令が通ってしまいます
result = client.read_holding_registers(address=0, count=1)
if not result.isError():
print(f"[データ取得成功] 現在のセンサー値: {result.registers[0]}")
else:
print("[-] データの読み取りに失敗しました。")
else:
print("[-] 機器に接続できませんでした。ネットワークを確認してください。")
finally:
# 通信を安全に閉じます
client.close()
print("[*] 接続を切断しました。")
このコードを見て、「えっ、こんなに簡単に機器のデータを読めちゃうの?」と思いましたよね。その感覚、大正解です。このコードに「書き込み(write_register)」の処理を加えれば、悪意あるユーザーが勝手に機器の設定を書き換えることができてしまいます。これが認証欠如の恐ろしさです。
—
4. どうやって守る?現場で実践できる防衛策
「じゃあ、古いプロトコルなんだから全部作り直さなきゃいけないの?」いいえ、稼働中の巨大な工場システムをごっそり入れ替えるのは現実的ではありませんよね。
私たちが現場で取るべき防衛策は、「家そのものを改築するのではなく、家の周りに頑丈な塀と門番を置く」アプローチです。
① ネットワークの完全な隔離(エアギャップ & 閉域網)
Modbus TCPデバイスは、絶対に直接インターネットに露出させてはいけません。ルーターやファイアウォールを適切に設定し、社内ネットワークや外部のインターネットから完全に切り離された閉域網(OTネットワーク)の中に配置しましょう。
② 産業用ファイアウォール(DPI)の導入
通常のファイアウォールは「IPアドレスとポート(例: 502番)」しか見ていませんが、産業用ファイアウォールはModbusの「中身(コマンドの種類やアクセスするレジスタのアドレス)」まで検査する DPI(Deep Packet Inspection) という技術を使います。
「この端末から、この危険な停止コマンド(機能コード 0x05 や 0x06 の特定アドレス書き込み)は通さない!」といった、細かい交通整理を行うのが効果的です。
③ VPNやセキュアなトンネリングの利用
もし拠点間でどうしても通信を行う必要がある場合は、IPsec VPNなどの暗号化されたトンネルを必ず使い、通信経費をのぞき見られないように保護します。
—
おわりに
今回は、Modbus TCPの認証欠如とコマンドインジェクションの脅威について、身近な例えを交えながら解説しました。
セキュリティの対策は、一朝一夕にはいきません。「自分たちの管理しているデバイスは、外から丸見えになっていないか?」「変なコマンドが飛んできたときに気づけるか?」という視点を持つことが、第一歩になります。
一歩ずつ、確実にセキュアなシステム構築のスキルを身につけていきましょう!次の記事でも、実践的なOT/IoTセキュリティのテクニックを分かりやすく解説していきますので、ぜひお楽しみに!
コメント