DARK MATTER

CDI Engineer's Technical Blog

Kali Linux で BitLocker ~ やってみる編 ~


Windows の BitLocker、Linux ユーザーにはとてもうらやましいですよね。
Trusted Platform Module(TPM)が搭載された PC なら手軽にディスクを暗号化できて、パスフレーズ入力無しで OS 起動できて。
そんな Windows のうらやま機能を Kali Linux でやっていきます。

続きを読む

続々 WiresharkのDissectorを使った独自プロトコル解析(TCP,UDP分割パケットの場合)

本稿では、Luaで独自プロトコルのDissectorを作る人のために、TCPとUDPの分割(フラグメント)パケットの再構築(リアセンブル)を説明します。

f:id:yasuikj:20200825183801p:plain

Dissectorって何?という人は、先にWiresharkのDissectorを使った独自プロトコル解析をやさしく解説してみましたを読んでください。

前々回は、符号なし整数、文字列を題材にDissectorを説明しました。 前回は、Bit列の解析や時刻の解析など様々なデータ型への対応や、エンディアン(Endian)の対応について説明しました。

これまでの内容を理解いただければ、1パケットの解析はできるようになったと思います。しかし、世の中にはデータサイズが大きく複数のパケットに分割されて送信されるプロトコルも存在します。今回、このような分割パケットのDissectorの作り方について解説します。

今回紹介する内容を理解いただくと、分割パケットに対応できるDissectorを作る力がつきます。
サンプルのキャプチャデータも添付するのでWiresharkを使って試してみてください。

技術部の安井です。長年、制御システムを開発した経験から、現在は制御システムセキュリティ向上に取り組んでいます。

前々回 前回とも、継続してアクセスいただいており、独自プロトコルを解析するためにDissectorを作成しようしている方が参考にしてくれているようです。記事を読みDissectorを作成する方が増えてくれていれば嬉しい限りです。
最近、前回ブログで「記載していないこと」と書いた「データサイズが大きく複数パケットに分割された場合のDissector」についての問い合わせをいただく機会がありました。TCPとUDPにおける分割パケットの解析方法の資料を探したところ、TCPに関しては多くの資料が見つかりましたが、UDPに関しては理解しやすい資料をさくっと見つけることができませんでした。このためUDPに関して解説するブログを書いてみることにしました。

対象読者

前々回、前回の以下ブログ内容を理解している方。かつ、何らかのプログラム言語を使ったことがあり配列や連想配列が何かを理解している方。
io.cyberdefense.jp
io.cyberdefense.jp

できるようになること

複数のパケットに分割されたパケットのDissectorの作成

TCPのパケット分割について(いちおう書いておきます)

TCPはストリーム型の通信であり、送信サイズや通信環境によりTCPの仕組みでパケットが分割されて送信される場合があります。このため一般に公開するDissectorでは分割パケットの対応はお作法として実施しておいた方がよいと思います。

TCPの分割パケットの解析については、pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT というキーワードを覚えておけば、必要な際にサンプルを探せばいろいろな解説資料がみつかると思います。わかりやすく親切に解説してくれていると思った2つのURLを紹介しておきます。
Wiresharkで独自プロトコルの解析 - Qiita
Wiresharkの解析プラグインを作る ssmjp 201409 P24,25

UDPのパケット分割について(ここから本題です)

制御システムではTCPよりオーバヘッドの小さなUDPを使う場面が多くみられ、大きなデータをUDPで送信する場合、送信プログラムにて1パケットで送信可能なサイズで分割して送信することが多いです*1

本稿では以下の例を用いてUDPの分割パケットの解析について解説します。

  • UDPで2つのパケットに分割(フラグメント)された内容を再構築(リアセンブル)して表示する。

送信したいデータは、図1に示した30byteのデータとする。


f:id:yasuikj:20200826171526p:plain
図1:UDPを使って送信するデータのイメージ
Size部は10進数の26,データ本体部はasciiコードのa〜zです。

UDPの1つのパケットのフォーマットは図2に示したとおりであり、データ部として最大16byteしか格納できないとする。

f:id:yasuikj:20200825172927p:plain
図2:UDPの1パケットのフォーマット

30byteのデータを図2のフォーマットで送信するには、パケットを分割する必要があるため、図3に示したように2つのパケットに分割して送信する。

f:id:yasuikj:20200825172939p:plain
図3:送信したいデータをUDPの2つのパケットに分割したイメージ

UDP分割パケットのDissector

この章は、本ページ内に記載したDissectorのサンプルコードをudp_div.luaという名称で保存し、udp_div.txtのパケットを読み込んでみてください。

proto = Proto("udp_div","udp_div")

Ident_F  = ProtoField.new("Ident","Ident",ftypes.UINT16)
DivNo_F  = ProtoField.new("DivNo","DivNo",ftypes.UINT16)
DivMax_F = ProtoField.new("DivMax","DivMax",ftypes.UINT16)
DataSize_F  = ProtoField.new("DataSize","DataSize",ftypes.UINT32)
Data_F   = ProtoField.new("Data","Data",ftypes.STRING)

proto.fields = { Ident_F, DivNo_F, DivMax_F, Size_F ,DataSize_F, Data_F}

-- 初期化処理
function proto.init()
  fragments = {} -- 1パケットずつに分割されたパケットのデータ部を保存するバッファ。各パケット毎に保存する
  concats = {}   -- 分割パケットをマージした本体データを保存するバッファ。DivMax目のパケット処理時に保存する
end

-- Dissector  解析のメイン部分
function proto.dissector(buffer, pinfo, tree)

  local ident_no   = buffer(0,2):uint()    -- Ident識別子
  local division_no  = buffer(2,2):uint()  -- DivNo
  local division_max = buffer(4,2):uint()  -- DivMax

  if pinfo.visited == false then    -- 当該パケットを処理するのが初めての場合
    --注意:このpinfo.visitedで判定しないとWiresharkの画面でパケットをクリックする度処理が動いてしまう
    if division_no == 1 then
      local data_size = buffer(6,4):uint() -- データ本体のトータルサイズ
    end
    local reassembly_byte     -- 組み立て後のデータバイト列

    -- fragmentsを保存するテーブルの枠を生成
    if fragments[ident_no] == nil then
      fragments[ident_no] = {}
    end
    if fragments[ident_no][division_no] == nil then
      fragments[ident_no][division_no] = {}
    end

    -- パケットのUDPデータ部のサイズから先頭の独自ヘッダサイズ(6byte)を除いた部分をfragmentsに記憶
    fragments[ident_no][division_no] = buffer:bytes(6,buffer:len()-6)

    -- 分割パケットの最後なら、分割パケットをまとめたバイト列を生成しconcatsに記憶
    if (division_no == division_max ) then
      -- 保存用バイト列を生成
      reassembly_bytearray = ByteArray.new()
      -- 分割数分処理
      for key, value in ipairs(fragments[ident_no]) do
        -- バイト列をマージ
        reassembly_bytearray:append(value)
      end
      -- 分割数分マージしたバイト列をconcatsに記憶
      concats[pinfo.number] = reassembly_bytearray
      -- 各分割パケットのバイト列を保存したエリアは解放
      fragments[ident_no] = nil
    end
  end

  tree:add(Ident_F,buffer(0,2))    -- Ident表示
  tree:add(DivNo_F,buffer(2,2))    -- DivNo表示
  tree:add(DivMax_F,buffer(4,2))   -- DivMax表示

  -- 分割パケットのまとめがある場合
  if concats[pinfo.number] ~= nil then
    pinfo.cols.info = "merged data"
    buffer1 = concats[pinfo.number]:tvb("merged data")
    tree:add(DataSize_F,buffer1(0,4))     -- Size部分表示
    tree:add(Data_F,buffer1(4,data_size)) -- Size部分以降のデータ本体表示
  end
end

--  Dissectorを使用するUDPポート番号を指定する。
udp_table = DissectorTable.get("udp.port")
udp_table:add(4352, proto)

テスト用データのパケットキャプチャデータをテキスト形式としたものを以下に記載します。
記載内容をudp_sample.txtというファイル名で空のテキストファイルに転記し保存した上、Wiresharkのメニューの[ファイル]-[開く]からudp_sample.txtを選択してください。

+---------+---------------+----------+
01:03:35,089,675   ETHER
|0   |08|00|27|db|63|e0|08|00|27|63|e1|01|08|00|45|00|00|32|5f|41|40|00|40|11|94|50|c0|a8|01|01|c0|a8|01|02|f7|51|11|00|00|1e|47|59|00|33|00|01|00|02|00|00|00|1a|61|62|63|64|65|66|67|68|69|6a|6b|6c|

+---------+---------------+----------+
01:03:35,146,884   ETHER
|0   |08|00|27|db|63|e0|08|00|27|63|e1|01|08|00|45|00|00|30|5f|41|40|00|40|11|94|50|c0|a8|01|01|c0|a8|01|02|f7|51|11|00|00|1c|47|33|00|33|00|02|00|02|6d|6e|6f|70|71|72|73|74|75|76|77|78|79|7a|

+---------+---------------+----------+

このDissectorでテスト用データをWiresharkで表示したものを図4に示します。2パケット目の"Data" 部にabcd〜xyz とマージされたデータが表示されているのがわかると思います。

f:id:yasuikj:20200825174646p:plain:w290f:id:yasuikj:20200825174703p:plain:w290
          図4:1パケット目と2パケット目のWiresharkでの表示

最後に、2パケット目の"Data"部をクリックしたときの表示を図5に示します。ソースコード上concats[pinfo.number]:tvb("merged data")とした部分が、画面の最下部の左側Frameバイト列の枠の右横にmerged data(30bytes)として別枠で表示されているのがわかると思います。

f:id:yasuikj:20200825174719p:plain
図5:リアセンブルしたデータ部を表示したもの

まとめ

本稿では、Luaを使ってUDPの分割パケットのDissectorを作る方法を説明しました。

本稿がUDPの分割パケットの解析に困っている方の助けになれば幸いです。



本稿を作成するにあたり参考とさせていただいた資料です。
osqa-ask.wireshark.org

補足

本記事を作成したところ、ある同僚の方より
「独自ヘッダーの情報だけでリアセンブリすると、クライアントが複数存在する場合バグりそうです。1対1を基本とする独自プロトコルや運用はよくありますが、dissectorとしては多対多で正しく動作できるよう、サーバー/クライアントのIP/ポートの組み合わせを使うとよさそうだと思います。」
とのアドバイスとともに、対策したサンプルソースをいただけました。上記以外の元ソースとの相違としては、pinfo.cols.infoの書き換えはやめており分割全パケットでマージ結果を表示するようにしている点と、パケットの到着順序逆転にも対応するため分割パケット組み立て用に確保したエリアの解放やめています。こちらの方が便利な場合も多々あると思いますので合わせて公開しておきます。ソースの解説は載せてませんのが興味ある方は読み解いてみてください。

*1:様々な理由がありますがここでは理由の説明は割愛します。

続きを読む

ふぉっふぉっふぉ、今日はワシのかんがえた最強の入退室システムの話じゃ。

はじめに

石垣です。

前回の記事続編としてIoT特有のセキュリティ対策具体例をご紹介したいと思います。

io.cyberdefense.jp

弊社ではハードウェア診断を行っているため、お客様から具体的な対策を教えてほしい等の相談を受けますが、診断報告書による大まかな脆弱性修正方法および参考資料、報告会での技術的な回答、相談を受けた際のコンサルティングのみとなっており実際に製品を作るお仕事はしておらず、お見せする実装がございませんでした。

もしかするとセキュリティ診断会社は指摘事項を見つけるだけで、実際のところ設計とか実装とかできないでしょ!!!???と思われているかもしれませんので実証もかねてIoT特有のセキュリティ対策を行った入退室システムを本気で作ってみました。

f:id:tatac1:20200731113809j:plain

Yubikey 5 NFCをカードリーダにかざすことでドアが開く仕組みとなっています。

皆さんが利用されているSuica/PASMO等FeliCaを利用したICカードと同じ使い勝手ですが、内部の仕組みや利用技術は全く異なります。

www.youtube.com

※モザイク適当なのとデモ向けなのでPINが初期値なのはご愛嬌です

昨年9月頃から作業を開始し今年の2月頃に基本構成が完成しました。

実は今年2月にカルフォルニアで行われたRSAカンファレンスで展示も行っております。

作ったもの

今回はNFCカードリーダ側とドアの開閉制御を行うサーバ側を含め開発しました。

設計は一から考えると大変なので米国連邦政府の規格であるPhysical Access Control System (PACS1)

pacs.idmanagement.gov

BACnet

http://www.bacnet.org/Bibliography/BACnet-Today-06/28889-Ritter.pdf

の規格を参照し実装しています。

しかしながら参照規格では、NFCカードリーダ、認証サーバ等をどのようにセキュアにすべきかIoT特有のセキュリティ対策について記述はないため以下の実装を行っています。

  • デバイス認証、署名のために証明書を利用、秘密鍵はTPMを利用し保護(ユニーク性/真正性の担保)
  • Secure bootで改ざんを検知(完全性の担保)
  • Full Disk Encryption(FDE)対応でディスクデータを暗号化(機密性の担保)
  • 各NFCカードリーダ、認証サーバ間はwebsocket over TLS1.3通信(機密性/完全性の担保)

f:id:tatac1:20200721154333j:plain
構成図

f:id:tatac1:20200720165157p:plain
シーケンス図

通信はすべてTLS1.3となっているので、クライアント認証を突破しない限りTLSより上位レイヤーヘの攻撃は到達しません。したがってアプリケーションおよびアプリケーションミドルウェアに脆弱性が見つかったとしても正規証明書が無い限り攻撃は到達しない為、結果的に緩和策となります。

弊社では過去に警備会社や重電メーカの入退室管理システムを利用していましたが、全く他のシステムと連動できなかったためActive Directory/LDAPとの連動を前提として設計し運用を楽にする集中一括管理の仕組みを取り入れています。

またログに関しても解錠要求記録は電子署名されているため改ざん対策のログとして利用可能です。

上記の動画で見ていただいたハードウェアですがTPMが組み込まれた産業システム向けのCPUボードを利用しており耐久性も考慮しています。

最終的なイメージ

f:id:tatac1:20200720214142p:plainf:id:tatac1:20200720214210p:plain

上記イメージのディスプレイにはkindle等で利用されているe-ink社のディスプレイを備える予定です。

今回e-ink ディスプレイを採用した理由ですが

  • 電力が喪失しても画面が表示可能であることから、有事の際の避難経路等のメッセージ表示が可能
  • 視認性のよいお知らせ、案内表示が可能
  • タッチパネルが備わっているため簡単な操作が可能

となります。

秋月や千石等では、様々な電子ペーパーディスプレイが販売されていますが、6インチ、解像度:758 x 1024 pixels,、タッチパネル、LEDバックライト、応答速度すべてを備えたディスプレイは販売されていないため、実はe-ink社からディスプレイの調達を行い、表示やバックライト、タッチパネル向けの制御ボードを自社開発しました。

f:id:tatac1:20200731124840j:plain
ディスプレイコントローラボード

またサーバも同様にTPMが組み込まれた産業システム向けのCPUボードを利用しており汎用製品で構成しているのでコストは専用製品と比べ廉価です。

電気錠を開ける制御ですがFPGAで回路を組みつつ、制御ボードをフルスクラッチから作りました。

f:id:tatac1:20200731113802j:plain
左からIO制御ボード+FPGAボード、サーバ側ボード

なお初期バージョンの電気錠制御はリレースイッチでした。

f:id:tatac1:20200804112639j:plain
リレースイッチ

ドッグフードを食べる

作成した入退室管理システムを実際に利用するために、社内すべての扉に工事を行っています。

美和ロック等2一般に販売されている電気錠であれば制御が可能な構成となっており、既存のカードリーダを置き換え3ることが可能です。

動画に映っていた黄色いケーブルは光ファイバーです。光ファイバーを利用することでLANケーブルの100m制約は無くなります。動画内で利用しているメディアコンバータでは最大50kmまで延長することが可能であり、ノイズ、落雷等による影響を抑えることが可能です。

動画ではドアを解錠したYubikey 5 NFCでWindowsにスマートカード認証ログオンを行っています。この認証の仕組みはActive Directoryに備わっている標準機能ですので、サーバ、クライアントともに別途ソフトウェアのインストールを行う必要はありません。またウェブアプリケーションへのアクセスの際にもクライアント証明書認証を行っています。

LinuxでもSSO認証(kerberos認証)が可能であることを社内では検証済みです。なおコロナの影響で検証はまだ行えていませんがActive Directoryと連動しMacでもスマートカード認証+SSOが行える事はApple公式資料で確認済みです。したがってWindows同様にMac標準機能でも実現可能です。

弊社ではYubikey内の証明書とOS標準機能を利用して

  • 802.1xを利用しWiFi, LAN接続時にEAP-TLS認証
  • VPN接続時のクライアント証明書認証
  • SMTP接続時のクライアント証明書認証
  • ウェブにおけるクライアント証明書認証

等を実現し物理セキュリティ、ネットワークセキュリティからアプリケーションレイヤーまでをカバーするパスワードレス認証、アカウントの窃取対策を行っています。

したがって

  • ドアや壁の破壊できればもちろん侵入は可能ですが、入退はYubikeyが無い限り侵入はとても難しいです。
  • 掃除の方が気軽にLANポートやWiFiにつなごうとしても、Yubikeyが無い限りネットワークにつながらないので社内ネットワークに接続することはとても難しいです。
  • 社内ネットワークに接続できたとしても、Yubikeyが無い限りアプリケーションレイヤーへのアクセスすることはとても難しいです。

弊社でのYubikey活用具体例の記事がありますので興味がある方はご覧ください。

io.cyberdefense.jp

io.cyberdefense.jp

余談:Suica/PASMO等のFeliCaを利用した入退室管理システム製品 ~ IDmの闇

IDmを使った認証の問題をご存じの方は読み飛ばしていただければと。

入退室管理システムではよく使われるICカードとしてFeliCaが利用されていますが、利用/実装方法を誤った製品のセキュリティ問題が指摘されています。

IPA:入退管理システムにおける情報セキュリティ対策要件チェックリスト www.ipa.go.jp

itmedia: なりすましの問題について記事 blogs.itmedia.co.jp

またフェリカネットワークスから公式に注意が行われています。

引用: モバイル FeliCa IC チップにおける製造 ID(IDm)の取り扱いについてhttps://www.felicanetworks.co.jp/assets/pdf/rule_plugin_idm.pdf

· モバイルFeliCa ICチップのIDmは、比較的容易に読み出しが出来るコードであり、FeliCa技術方式のセキュリティ機能をフルに活用したものではありません。セキュリティの観点から次の点にご注意ください。 · IDmは誰でも読み出すことができますので、これのみを用いたアプリケーションは、正規カードになりすました偽造カードやカードエミュレータにより攻撃を受ける可能性があります。 · 通信路での暗号化をしておりませんので、盗聴される可能性があります。 · セキュリティが要求されるアプリケーションにおいては、FeliCa技術方式の相互認証機能の利用を推奨します。 また、ユニークなIDを必要とするFeliCaサービスアプリケーションを開発する際には、IDmではなくサービス事業者がサービスレベルで付番管理するコードを利用することを推奨します。

実際にIDmのみを参照し認証を行っている製品を弊社ではいくつかの製品で確認しています。

FeliCaのセキュアエレメント領域を利用し無い限りセキュアな認証を実現することは難しく、以下の様なSDKを利用する必要があります。

www.sony.co.jp

FeliCaは公開鍵4ではなく共通鍵AES/DESを利用しています。共通鍵を利用し高速処理を実現することと引き換えに安全な鍵管理・保護の仕組みが必要となります。

www.sony.co.jp

そのためNFCカードリーダには、AES/DES等の鍵をセキュアに保存するSAMチップを利用する必要があります。

www.sony.net

また一部入退室管理システムのスタンドアロン方式ではカードリーダは電気錠をコントロールするIOコントロールボードへ結線され、開錠、施錠信号が送信される仕組みとなっている構成があります。つまりカードリーダからIOコントロールボードへ伸びたケーブルの通信をタッピングしリプレイ攻撃が有効となるケースも考えられます。

通信ケーブルのタッピングは弊社の過去記事で取り上げていますので、現実的な脅威と考えられます。

io.cyberdefense.jp

皆さんのオフィスの入退室システムはどのような方式で開閉を行っているか把握されているでしょうか?

お手持ちのPASMOやSuica等を入退室以外で利用されているのであれば何処で利用したか把握されているでしょうか? IDmが何処で読み取られたか把握されているかたはいるでしょうか?

もし現在ご利用の入退室管理システムに「お手持ちのICカードで○○機能がご利用できます」と記載がある場合どのような認証方式であるか穿ったみかたをした方がよいかもしれません。

物理はセキュリティ対策の根幹であり非常に重要ですので、是非一度はIPAから提供された資料を参考にチェックを行ってみることをおすすめします。

  • 本サイトに掲載されている商品またはサービスなどの名称は、各社の商標または登録商標です。
  • 本サイトはリスク把握・対策を目的としており、著作権侵害や不正アクセス行為等の教唆、幇助を目的としたものではありません。

  1. ※FIPS140対応の暗号モジュールを利用し、PACSテストにパスをすれば米国連邦政府でも利用可能となります。国産では残念ながらPACS認証を取得した入退室管理システムは有りません。

  2. ゴール等他社の電気錠もFPGA側の変更で対応可能となっています。

  3. LANケーブルと電源ケーブルがあればカードリーダ側を取り替えるだけとなります。

  4. 公開鍵はサポートしていないためWindows/Macのスマートカード認証、TLSクライアント認証,802.1x等の利用はOS標準機能では実現できません。

株式会社サイバーディフェンス研究所 / Cyber Defense Institute Inc.