OT セキュリティのトラブルシューティングのための異常なプロトコルの解析方法

OT セキュリティのトラブルシューティングのための異常なプロトコルの解析方法

OT セキュリティ研究者として、Nozomi Networks Labs チームは、OT およびIoT デバイスプロセスとそのセキュリティリスクを理解するために継続的に取り組んでいます。これには、組込みコントローラのようなアセットが、どのように互いに、そしてワークステーションと通信するかを理解することも含まれます。そのためには、文書化されていないプロトコルを逆引きする必要があります。

残念ながら、ほとんどのベンダーがシステムを設計する際に、未知の複雑なレイヤーを設けているため、解剖のプロセスを標準化することはできない。そこで、セキュリティ研究者の経験が大きな違いを生むことになる。

この記事はNozomi Networks Labs の連載記事の第一回目で、Lua API を使って Wireshark に文書化されていないプロトコルを正しく分解するよう指示する方法を紹介します。

このブログでは、実際のユースケースである、よく知られている Cisco Nexus プロトコル用のディセクタを開発する際のステップについて見ていく。また、GitHubにプラグインを投稿し、広くセキュリティ・コミュニティの助けとなるようにした。

あなた自身がセキュリティ研究者であろうと、資産所有者のためにネットワークを管理する人であろうと、この方法論とプラグインは、ネットワークの問題をトラブルシューティングし、全体的なOT セキュリティを向上させるのに役立ちます。

未知のプロトコルの解剖方法の決定

未知のプロトコルの探索プロセスを開始するためによく使われるツールのひとつにWiresharkがある。

コントローラ間で特定のタイプの通信を強制することによって生成された、適切なトラフィック/キャップのセットがあれば、プロトコルの解析を開始できる。

まず、パターンに注目することから始める。通常、プロトコルのリバースエンジニアリングを始めると、未知の言語に直面することになる。通信構造を段階的に理解するのに役立つ重要な要素(長さ、ファンクションコード、シーケンス番号、CRCなど)を特定する必要がある。

言語パターン
プロトコルのリバースエンジニアリングは、未知の言語パターンに注目することから始まる。Lua言語で書かれたプラグイン・スクリプトは、パケットを解析し、研究結果を検証するのに役立つ。

この段階で仮定を行う際、プラグインと呼ばれるWiresharkの機能の一つを活用することが役立ちます。プラグインとは、Luaプログラミング言語で書かれたスクリプトのことで、私たちが発見した情報を使って各パケットを解析するようツールに指示します。プラグインを使用すると、収集したトラフィックやライブトラフィックで調査結果を検証することもできます。

ヒント: パフォーマンスを微調整する必要がある場合は、ネイティブのWireshark C言語を使用して、独自のディセクタを直接作成することもできます。

  • Windows: %APPDATA%Wiresharkplugins
  • Unix~/.local/lib/wireshark/plugins
  • Mac~/.config/wireshark/plugins
ロックウェル・イーサネット/IPの解剖
ロックウェル・イーサネット/IPの解剖

ご想像の通り、未知のコミュニケーション言語を完全に理解するためのプロセスは、退屈で時間のかかるものです。しかし、最終的には(プラグインという形で)共有可能な知識となり、他の人にとって非常に有益なものとなる。

例えば、ユーティリティ・オペレーターは、通常の産業プロセス操作の中で特定のシナリオのトラブルシューティングが必要になるたびに、このようなツールから多大な恩恵を受けることができる。

Luaディセクタをゼロから開発する方法を説明するのではなく(簡単に見つかるドキュメントがすでにたくさんあります。

ヒント:Luaディセクションの旅を始めたばかりの方は、Mikaの技術ブログをご覧ください: LuaでWiresharkディセクタを作成する - パート1(基本編)。

新しいディセクタの登録

エーテルタイプとリコール

最初の課題は、Wiresharkでは簡単にアクセスできないプロトコルを扱うことである。

NX-OSスイッチ・シリーズ間で使用されている有名なプロトコルであるCisco Nexusを例にしてみよう。関連するディセクタ(内部構造もリバース・エンジニアリングしていることに注意)を開発する手順を説明する。

まず研究チームは、Wiresharkがこのようなプロトコルの解析をサポートしていないことに気づいた。つまり、その構造を理解するためには、ちょっとした調査とパケット解析をしなければならない。

Wiresharkが知る限り、802.1Q Virtual Lanフレームがある。これは、VLAN(仮想 LAN)を定義するために一般的に使用されている規格で、かなり基本的な構造を持っています。

配置されている VLAN ID [0x8905]は非標準である。このため、ツールはこれを「不明」タイプに分類している。これがプロプライエタリ・プロトコルの最初の指標になる可能性があると仮定して、後のために覚えておこう。

プロトコル不明
プロトコル不明

パケットの "データ "内容に見られるいくつかの興味深いパターンをもう少し深く分析した結果、その構造は予想以上に単純であることが判明した。そして、ある点から見ると、産業分野でよく使われている別のプロトコルと非常によく似ている。このプロプライエタリ・プロトコルは、実際にはベンダー固有のレイヤーとよく知られたプロトコルの組み合わせである。

ヒント:0x88a4バイトに心当たりは?

幸運なことに、カプセル化されたプロトコルはWiresharkによってすでに知られている。つまり、未知のレイヤーがワイヤーを通過するたびに、それを適切かつ正確に検出するために、未知のレイヤーをサブスクライブ(タグ付け)するようツールに指示する必要がある。

ここで、先ほどのカプセル化されたディセクタを思い出してほしい。

イーサネットIIのフレーム構造
イーサネットIIのフレーム構造

まずはコードを書いてみよう。まず、Wiresharkに、不明なType ID: 0x8905のイーサネットパケットを見るたびに、ディセクタにリンクするように指示しなければならない。

適切にリンクするには、標準のudp/tcp.portではなく、`ethertype`パラメータ[別名Type ID]のみを参照することに興味があることを示すことで、`DissectorTable.get()`関数が指定されたフレーム領域を指すように強制することができます。

-- ラッパーフィールドの初期化 -- ラッパーのメイン関数 関数 cisco_nexus.dissector (buf, pkt, root) 終了 -- 0x8905 タイプの Ethernet パケットを購読する。 local eth_table = DissectorTable.get("ethertype") eth_table:add(0x8905, cisco_nexus)

次に、特定のオフセットでリコールする2つ目のディセクタ・テーブルを初期化しなければならない。このテーブルには、別のアプローチを使う:Luaは、get_dissector()関数を使うことで、必要なときにいつでも特定の既知のディセクタを指定できるようにしてくれている。

これらの機能を実際に使ってみよう。

ネストされたプロトコルは802.1Q IEEE標準の中で定義されたVLANタグを持っているので、 スクリプトの初期化セクションで、それに関連するDissectorTableを `original_vlan_dissector` 変数に格納することができる:

-- ロード 802.1Q バーチャル LAN ディセクタ original_vlan_dissector = DissectorTable.get("ethertype"):get_dissector(0x8100)

そして、Cisco Nexusのヘッダーの後の正しいオフセットで、メインのディセクション関数のコンテキスト内で、正確に4ヘッダーバイトの後にそれを呼び出す:

ヒント:最初の長さのチェックは、万が一0バイトのパケットが見つかった場合に、それを確実に避けるために行われる。

-- ラッパーのメイン関数 関数 cisco_nexus.dissector (buf, pkt, root) -- パケットの長さが適切かどうかを確認する。 if buf:len() == 0 then return end pkt.cols.protocol = cisco_nexus.name -- Cisco Nexus用のサブツリーを作成する。 サブツリー = root:add(cisco_nexus, buf()) -- ECATディセクタを購読する original_vlan_dissector:call(buf:range(4,buf:len()-4):tvb(), pkt, subtree) 終了

最終的な結果は、パケット構造全体の完全な解剖である。

前未知のプロトコルの検出
前未知のプロトコルの検出
その後未知のプロトコルの内部構造を最終解剖
その後未知のプロトコルの内部構造を最終解剖

Cisco Nexusプロトコルを使用してCisco Nexus Dissectorプラグインを作成する

この記事では、Lua APIを使用して、既知および未知のレイヤー2フレームを簡単に管理する方法を、解析中にWiresharkに適切に分解するように指示することで示しました。これを説明するために、Nozomi Networks の研究者は、これまで知られていなかったプロトコルの実例を使用しました:Cisco Nexusである。

背景を分析する中で、チームは独自プロトコルが明確に定義された通信構造を内包していることを発見した。そして、この知識を活用し、以下のDissectorTable関数の組み合わせをテストした:

  • .get(v1)
  • .get(v1):get_dissector(v2)
  • .get(v1):get_dissector(v2):call(v3,v4,v5)

私たちの研究の成果は、Cisco Nexususctorと呼ばれるプラグインです。このプラグインはGitHubに公開されており、アセット・オーナーが自分のネットワーク内のアクティビティをトラブルシューティングするのに役立っている。また、グローバルなセキュリティ・コミュニティも、分析や研究プロジェクトを進めるために使用することができます。

来月、Nozomi Networks Labsは、一般的に使用されている産業用通信機器に見られる別の未知のプロトコル用のプラグインを作成する方法を調査する予定です。ご期待ください!

参考文献

  1. https://mika-s.github.io/wireshark/lua/dissector/2017/11/04/creating-a-wireshark-dissector-in-lua-1.html
  2. https://en.wikipedia.org/wiki/IEEE_802.1Q
  3. https://wiki.wireshark.org/Protocols/ethercat
  4. https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html#lua_class_DissectorTable
  5. https://www.wireshark.org/docs/wsug_html_chunked/ChPluginFolders.html
  6. https://github.com/NozomiNetworks/dissectors