VM でカーネルメモリの改ざんの兆候を確認する

このページでは、Virtual Machine Threat Detection のカーネルモード ルートキットの検出結果の有効性を確認するために実行できるタスクについて説明します。カーネルモード ルートキットの検出結果は、VM のカーネルメモリがマルウェアによって改ざんされている可能性があることを示します。

VM Threat Detection からカーネルモード ルートキットの検出結果が返された場合は、影響を受ける Compute Engine インスタンスで次の Linux コマンドを実行して、システム呼び出しの不正使用や隠れたカーネル モジュールなど、異常を示す可能性のあるデータポイントを探すことをおすすめします。

また、影響を受ける VM で提供されているデータ収集スクリプトを実行することもできます。このスクリプトは、このページで説明するコマンドを実行します。

特に記載のない限り、このページの各検査タスクは、すべてのカーネルモード ルートキットの検出結果に関連しています。

このドキュメントの前提条件は次のとおりです。

  • このドキュメントで説明するタスクは、VM Threat Detection からカーネルモードのルートキットの検出結果を受け取った後に行います。関連する検出結果のカテゴリのリストについては、カーネルモード ルートキットの脅威の検出をご覧ください。

  • Linux コマンドライン ツールと Linux カーネルを理解している。

VM Threat Detection について

Virtual Machine Threat Detection は、エンタープライズ ティアとプレミアム ティアで利用できる Security Command Center の組み込みサービスです。このサービスは、Compute Engine インスタンスをスキャンして、侵害されたクラウド環境で実行されている、悪質な可能性のあるアプリケーション(暗号通貨マイニング ソフトウェア、カーネルモード ルートキット、マルウェアなど)を検出します。

VM Threat Detection は、Security Command Center の脅威検出スイートの一部であり、Event Threat DetectionContainer Threat Detection の既存の機能を補完するように設計されています。

VM Threat Detection の詳細については、Virtual Machine Threat Detection の概要をご覧ください。VM Threat Detection の検出結果の詳細を表示する方法については、Google Cloud コンソールで検出結果を確認するをご覧ください。

始める前に

Security Command Center ですべてのリソースと検出結果を表示し、影響を受ける Compute Engine インスタンスを管理するために必要な権限を取得するには、管理者に次の IAM ロールを付与するよう依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

影響を受ける VM を特定する

  1. 検出結果の詳細を表示する
  2. [影響を受けるリソース] セクションの [リソースの完全な名前] フィールドで、リンクをクリックします。影響を受ける Compute Engine インスタンスの詳細ビューが新しいタブで開きます。
  3. インスタンスに接続します。詳細については、Compute Engine のドキュメントの Linux VM に接続するをご覧ください。

予期しないカーネル モジュールを見つける

VM に予期しないモジュールが存在する場合、VM のカーネル メモリが侵害されている可能性があります。

予期しないカーネル モジュールを確認する手順は次のとおりです。

  1. VM に読み込まれたすべてのカーネル モジュールを一覧表示します。

    lsmod
    cat /proc/modules
    
  2. 読み込まれたモジュールとアンロードされたモジュールの sysfs エントリを一覧表示します。

    ls -l /sys/module/
    
  3. これらのリストの結果を、プロジェクト内の他の VM のリストと比較します。影響を受ける VM に表示され、他の VM に表示されないモジュールを探します。

syslog でツリー外のモジュールを検索する

ツリー外のモジュールが VM に読み込まれた兆候は、異常なカーネル モジュールが読み込まれたことを示している可能性があります。カーネル ログ バッファと syslog メッセージを検索して、ツリー外のモジュールが読み込まれているかどうかを確認できます。ログエントリでは、ツリー外のモジュールは汚染された読み込みとしてマークされます。

カーネル ログ バッファと syslog メッセージで、次のようなログエントリを検索します。

MODULE_NAME: loading out-of-tree module taints kernel.
  • カーネル ログ バッファで、ツリー外のモジュールの存在を示すログエントリを検索します。

    sudo dmesg | grep out-of-tree
    
  • すべての syslog メッセージを検索して、ツリー外のモジュールの存在を示すログエントリを探します。

    grep "out-of-tree" /var/log/syslog*
    

ライブパッチ適用を確認する

VM でのライブパッチ適用は、VM Threat Detection の検出を妨げ、誤検出の検出結果をトリガーする可能性があります。

ライブパッチ適用を確認する手順は次のとおりです。

  1. syslog で、ライブパッチ モジュールのインストールとロギングを確認します。通常、ライブ パッチ適用は、カーネル ftrace ポイントをインストールしてカーネル コードを変更します。

    sudo grep livepatch /var/log/syslog*
    
  2. ライブパッチ適用用にインストールされた新しいカーネル モジュールを検索します(通常は livepatch が接頭辞として付いています)。

    sudo lsmod | grep livepatch
    
  3. パッチファイルを検索します。

    sudo ls -l /sys/kernel/livepatch
    

ライブパッチ適用の詳細については、Linux カーネルのドキュメントのLivepatchをご覧ください。

VM で検出されたその他の悪意のあるアクティビティを確認する

  1. Security Command Center で、調査中の VM Threat Detection の検出結果の詳細を表示します。
  2. [影響を受けるリソース] セクションの [リソースの完全な名前] フィールドで、プルダウン矢印をクリックし、[このリソースの完全な名前を含むすべての検出結果を表示] をクリックします。検出結果クエリが更新され、この VM の検出結果のみが表示されます。
  3. クリプトマイニングのアクティビティ、マルウェア、異常な IAM 付与、その他のセキュリティ脅威を示す検出結果を確認します。

ウイルス対策ソフトウェアが偽陽性検出の原因となっているかどうかを確認する

ウイルス対策ソフトウェアは VM Threat Detection の検出を妨げ、誤検出をトリガーする可能性があります。

システムで実行されているすべてのプロセスを確認する

予期しないプロセスが存在する場合、VM Threat Detection の検出結果が有効で、VM が侵害されていることを示している可能性があります。

  1. VM で実行されているすべてのプロセスを一覧表示します。

    ps -eAf
    
  2. この VM で通常は実行されないデバッガ プロセス(gdbstracepstack など)を探します。デバッガ プロセスは他のプロセスをスヌープできます。

  3. VM で他の不審なプロセスを探します。

起動したカーネルを確認する

起動したカーネルを確認して、Linux カーネルを特定します。

cat /proc/version

返された値が想定されるカーネル バージョンと異なる場合は、カーネル内の kexec ツールを悪用した不正使用攻撃が行われている可能性があります。kexec ツールを使用すると、システムをソフトブートして別のカーネルを使用できます。

Unexpected kernel code modification の検出結果の追加タスク

このセクションのタスクは、Defense Evasion: Unexpected kernel code modification 検出結果カテゴリに固有のものです。次のセクションのタスクを実行して、このカテゴリの検出結果の有効性を確認します。

これらのセクションでは、VM がデバッガ API を使用しているかどうかを確認します。デバッガ API は、実行中のカーネルのコード領域を変更できるため、誤検出の検出結果をトリガーする可能性があります。

通常、VM Threat Detection は、デバッガ API の使用を検出しても検出結果を生成しません。ただし、VM が VM Threat Detection に認識されていないデバッガ API を使用している場合、誤検出が発生する可能性があります。

有効になっているデバッグ トレーサーを確認する

トレーサー(nop トレーサーを除く)は、カーネル コードの変更を引き起こす可能性があります。これらは VM Threat Detection の検出を妨げ、偽陽性の検出結果をトリガーする可能性があります。通常、VM Threat Detection がトレーサーの存在を検出しても、Defense Evasion: Unexpected kernel code modification 検出結果は送信されません。

有効になっているデバッグ トレーサーを確認する手順は次のとおりです。

  1. 使用可能なトレーサーを確認します。

    cat /sys/kernel/debug/tracing/available_tracers
    

    出力は次のようになります。

    hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
    
  2. 現在のトレーサーを確認します。

    cat /sys/kernel/debug/tracing/current_tracer
    

    結果は、前のコマンドで返された使用可能なトレーサーの 1 つです。

  3. システムでトレースが有効になっているかどうかを確認します。

    cat /sys/kernel/debug/tracing/tracing_on
    

    1 は、システムでトレースが有効になっていることを示します。

  4. トレースが無効になっている CPU を一覧表示します。

    cat /sys/kernel/debug/tracing/tracing_cpumask
    
  5. トレース詳細を表示します。

    cat /sys/kernel/debug/tracing/trace_stat/function*
    

    出力は次のようになります。

    Function       Hit    Time            Avg             s^2
    

デバッグ トレーサー イベントを確認する

カーネルのイベント モニタリングにより、カーネルコードが変更され、VM Threat Detection の検出結果が誤検出される可能性があります。多くのデバッグツールとパフォーマンス モニタリング ツールでは、イベント モニタリングを自動的に有効にできます。

イベント モニタリングが有効になっているかどうかを確認するには、次のコマンドを実行します。

cat /sys/kernel/debug/tracing/events/enable
cat /sys/kernel/debug/tracing/events/*/enable

出力が 0 の場合、イベント モニタリングが無効になっています。出力が 1 の場合、イベント モニタリングが有効になっています。

イベント モニタリングを無効にして、VM Threat Detection が同じ検出結果を出力するかどうかを確認することを検討してください。検出結果が減った場合は、最初の検出結果の一部が誤検出だった可能性があります。

kprobe、eBPF ルール、netfilter を確認する

Netfilter、kprobe、eBPF ルールは、カスタム コールバックへの呼び出し転送をトリガーするため、コード変更をトリガーする可能性があります。VM Threat Detection は、これらのプローブの存在を検出し、それらを変更されたコードページにマッピングします。偽陽性をトリガーするプローブは考慮されません。

kprobe、eBPF ルール、netfilter を確認するには、次のコマンドを実行します。

iptable -L
cat /sys/kernel/debug/kprobes/enabled
cat /sys/kernel/debug/kprobes/list
cat /sys/kernel/debug/kprobes/blacklist
cat /sys/kernel/debug/tracing/enabled_functions
sudo apt-get update && sudo apt-get install bpftrace
bpftrace -l
sudo apt install linux-tools-`uname -r`
bpftool prog

早期デバッグ トレーサーを確認する

起動時に有効になっている早期デバッグ トレーサーが存在すると、VM Threat Detection の検出が妨げられ、誤検出が発生する可能性があります。

早期デバッグ トレーサーを確認するには、次のコマンドを実行します。

cat /proc/cmdline

使用可能なアーリーデバッグ トレーサーの一覧については、Linux カーネルのドキュメントの起動時のトレースをご覧ください。

Unexpected system call handler の追加タスク

Defense Evasion: Unexpected system call handler の検出結果が返された場合に、このタスクを実行します。

システム呼び出しを監査し、使用状況と呼び出し元の異常を探します。監査ログには、呼び出しプロセスとシステム呼び出しの引数に関する情報が記録されます。検証タスクを実行して、一般的なシステム呼び出しの想定される動作を確認することもできます。詳細については、このページのDiamorphine ルートキットを使用した検査の例をご覧ください。

Unexpected interrupt handler の追加タスク

Defense Evasion: Unexpected interrupt handler の検出結果が返された場合に、このタスクを実行します。

システム上のライブ割り込みハンドラを一覧表示し、結果をプロジェクト内の他の同様の VM の情報と比較します。予期しない割り込みハンドラは、VM が侵害されていることを示している可能性があります。

ライブ割り込みハンドラを一覧表示するには、次のコマンドを実行します。

cat /proc/interrupts

出力は次のようになります。

           CPU0       CPU1
  0:         44          0   IO-APIC   0-edge      timer
  1:          9          0   IO-APIC   1-edge      i8042
  4:      17493          0   IO-APIC   4-edge      ttyS0
  8:          0          0   IO-APIC   8-edge      rtc0
  9:          0          0   IO-APIC   9-fasteoi   acpi
 12:          0        152   IO-APIC  12-edge      i8042
 24:         16          0   PCI-MSI 81920-edge      virtio2-config
 25:          0      40194   PCI-MSI 81921-edge      virtio2-inflate
 26:      58528          0   PCI-MSI 81922-edge      virtio2-deflate
 27:          0     966356   PCI-MSI 81923-edge      virtio2-stats
 28:          0          0   PCI-MSI 49152-edge      virtio0-config
 29:          0          0   PCI-MSI 49153-edge      virtio0-control
 30:          0          0   PCI-MSI 49154-edge      virtio0-event
 31:          0     555807   PCI-MSI 49155-edge      virtio0-request
 32:          0          0   PCI-MSI 98304-edge      virtio3-config
 33:        184          0   PCI-MSI 98305-edge      virtio3-input
 34:          0          0   PCI-MSI 65536-edge      virtio1-config
 35:     556203          0   PCI-MSI 65537-edge      virtio1-input.0
 36:     552746          1   PCI-MSI 65538-edge      virtio1-output.0
 37:          1     426036   PCI-MSI 65539-edge      virtio1-input.1
 38:          0     408475   PCI-MSI 65540-edge      virtio1-output.1

Unexpected processes in runqueue の追加タスク

Defense Evasion: Unexpected processes in runqueue の検出結果が表示された場合は、次の手順を行います。このセクションでは、検出結果を調査するために追加のデータポイントを収集できます。これらのデータポイントは、マルウェアの問題を直接示しているわけではありません。

このタスクでは、CPU ごとのスケジューラ キューを確認します。一部のプロセスは存続期間が短い場合がありますが、CPU あたりの実行プロセスを使用してスケジューラ キューの動作を評価し、異常な動作を探すことができます。

  1. 実行中の各プロセスが CPU ごとに費やした時間の詳細を表示します。これにより、特定の CPU が非常にビジー状態かどうかを確認できます。結果を、/proc/interrupts から CPU に固定された割り込みに関連付けることができます。

    cat /proc/schedstat
    

    このコマンドの詳細については、Linux カーネルのドキュメントのスケジューラ統計情報をご覧ください。

  2. 現在の実行可能なタスクと、各 CPU のコンテキスト スイッチの詳細を一覧表示します。

    cat /proc/sched_debug
    

    出力は次のようになります。

    Sched Debug Version: v0.11, 5.4.0-1081-gke #87-Ubuntu
    ktime                                   : 976187427.733850
    sched_clk                               : 976101974.761097
    cpu_clk                                 : 976101973.335113
    jiffies                                 : 4538939132
    sched_clock_stable()                    : 1
    
    sysctl_sched
      .sysctl_sched_latency                    : 12.000000
      .sysctl_sched_min_granularity            : 1.500000
      .sysctl_sched_wakeup_granularity         : 2.000000
      .sysctl_sched_child_runs_first           : 0
      .sysctl_sched_features                   : 2059067
      .sysctl_sched_tunable_scaling            : 1 (logarithmic)
    
    cpu#0, 2199.998 MHz
      .nr_running                    : 0
      .nr_switches                   : 16250401
      .nr_load_updates               : 0
      .nr_uninterruptible            : 12692
      .next_balance                  : 4538.939133
      .curr->pid                     : 0
      .clock                         : 976101971.732857
      .clock_task                    : 976101971.732857
      .avg_idle                      : 880408
      .max_idle_balance_cost         : 500000
    
    runnable tasks:
     S           task   PID         tree-key  switches  prio     wait-time             sum-exec        sum-sleep
    -----------------------------------------------------------------------------------------------------------
     S        systemd     1     51740.602172    326778   120         0.000000    165741.786097         0.000000 0 0 /init.scope
     S       kthreadd     2   1482297.917240      1361   120         0.000000       112.028205         0.000000 0 0 /
     I      rcu_sched    11   1482642.606136   1090339   120         0.000000     17958.156471         0.000000 0 0 /
     S        cpuhp/1    15       537.058588         8   120         0.000000         2.275927         0.000000 0 0 /
     S  idle_inject/1    16        -2.994953         3    49         0.000000         0.012780         0.000000 0 0 /
     S    migration/1    17         0.000000    245774     0         0.000000      5566.508869         0.000000 0 0 /
     S    ksoftirqd/1    18   1482595.656315     47766   120         0.000000      1235.099147         0.000000 0 0 /
     I   kworker/1:0H    20       536.961474         5   100         0.000000         0.043908         0.000000 0 0 /
     S      kdevtmpfs    21     11301.343465       177   120         0.000000         3.195291         0.000000 0 0 /
     I          netns    22         6.983329         2   100         0.000000         0.021870         0.000000 0 0 /
     Srcu_tasks_kthre    23        10.993528         2   120         0.000000         0.010200         0.000000 0 0 /
     S        kauditd    24   1482525.828948       319   120         0.000000        14.489652         0.000000 0 0 /
    
  3. 次のものを確認します。

    • 実行中のプロセス名。
    • CPU あたりのコンテキスト切り替え数。プロセスが CPU でスイッチをあまり行っていないか、またはあまり行いすぎていないかを確認します。
    • 使用した CPU 時間(アイドル状態ではない時間)。

Diamorphine ルートキットを使用した検査の例

このセクションでは、Diamorphine ルートキットがインストールされている VM の検査について説明します。Diamorphine は、一般的な読み込み可能なカーネル モジュール(LKM)です。このルートキットは、次の検出結果カテゴリをトリガーします。

  • Defense Evasion: Unexpected system call handler
  • Defense Evasion: Unexpected kernel modules
  • Defense Evasion: Unexpected kernel read-only data modification

これらの検出結果カテゴリの詳細については、カーネルモード ルートキットの脅威の検出結果をご覧ください。

実施した検査手順と VM で確認された症状は次のとおりです。

  1. 読み込まれているすべてのツリー外カーネル モジュールを syslog で検索します。

    1. カーネル ログ バッファを検索します。

      sudo dmesg | grep out-of-tree
      

      出力:

      diamorphine: loading out-of-tree module taints kernel.
      
    2. syslog メッセージを検索します。

      grep "out-of-tree" /var/log/syslog*
      

      出力:

      /var/log/syslog: diamorphine: loading out-of-tree module taints kernel.
      
  2. syslog でモジュールの検証エラーがないか検索します(一部の Linux ディストリビューションでは使用できません)。

    1. カーネル ログ バッファを検索します。

      sudo dmesg | grep "module verification failed"
      

      出力:

      diamorphine: module verification failed: signature and/or required key missing - tainting kernel
      
    2. syslog メッセージを検索します。

      sudo grep "module verification failed" /var/log/syslog*
      

      出力:

      /var/log/syslog: diamorphine: module verification failed: signature and/or required key missing - tainting kernel
      
  3. モジュールが /proc/modules コマンドと lsmod コマンドから非表示になっていることを確認します。

    sudo grep diamorphine /proc/modules
    sudo lsmod | grep diamorphine
    

    結果は表示されませんでした。

  4. モジュールに sysfs にエントリがあることを確認します。

    sudo cat /sys/module/diamorphine/coresize
    

    出力:

    16384
    
  5. アーキテクチャのシステム コール テーブルを取得します。

    sudo ausyscall --dump
    

    出力:

    Using x86_64 syscall table:
    0       read
    1       write
    2       open
    3       close
    

    通常は rootkit によって改ざんされるシステム呼び出し(killgetdents など)の異常を監査します。

  6. システムコール ハンドラの改ざんを確認するには、システムコールを監査して異常な動作がないか確認します。これらの動作は、システム呼び出しごとに異なります。

    通常ハッキングされるシステムコールは kill 呼び出しです。kill システム呼び出しがバイパスされたかどうかを確認できます。次の例では、kill システム呼び出しが監査されました。

    1. auditd をインストールし、Diamorphine ルートキットのない VM の動作を確認します。

      $ sudo apt-get update && sudo apt-get install auditd
      $ # Add audit rules for specific system calls
      $ sudo echo "-a exit,always -F arch=b64 -S kill -k audit_kill" >> /etc/audit/rules.d/audit.rules
      $  sudo /etc/init.d/auditd restart
      Restarting auditd (via systemctl): auditd.service.
      
      $ # Behavior observed without rootkit
      $ sleep 600 &
      [1] 1119
      $ sudo kill -9 1119
      $ sudo ausearch -k audit_kill | grep -A 3 "pid=1119"
      type=OBJ_PID msg=audit(1677517839.523:198): opid=1119 oauid=1001 ouid=0 oses=1 obj=unconfined ocomm="sleep"
      type=SYSCALL msg=audit(1677517839.523:198): arch=c000003e syscall=62 success=yes exit=0 a0=45f a1=9 a2=0 a3=7f61c64b2ac0 items=0 ppid=1034 pid=1035 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
      tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj=unconfined key="audit_kill"
      $ sleep 600 &
      [1] 1087
      $ sudo kill -31 1087
      $ sudo ausearch -k audit_kill | grep -A 3 "pid=1087"
      type=OBJ_PID msg=audit(1677517760.844:168): opid=1087 oauid=1001 ouid=0 oses=1 obj=unconfined ocomm="sleep"
      type=SYSCALL msg=audit(1677517760.844:168): arch=c000003e syscall=62 success=yes exit=0 a0=43f a1=1f a2=0 a3=7f61c64b2ac0 items=0 ppid=1034 pid=1035 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0        ses=1 comm="bash" exe="/usr/bin/bash" subj=unconfined key="audit_kill"
      

      検査のこの時点で、Diamorphine ルートキットがインストールされていました。次の手順では、ルートキットのインストール後の VM の動作を示します。

    2. Diamorphine ルートキットがインストールされた後、シグナルの監査ログエントリが存在しないことを確認します。

      $ sudo ausearch -k audit_kill | grep -A 3 "pid=1158"
      $ sleep 600 &
      [2] 1167
      
    3. シグナルの監査ログエントリの詳細を確認します。この例では、この特定のシグナルは rootkit によって完全に不正使用されていませんが、呼び出し元のプロセスに関する情報は利用できます。

      $ sudo kill -9 1167
      $ sudo ausearch -k audit_kill | grep -A 3 "pid=1167"
      type=OBJ_PID msg=audit(1677518008.586:237): opid=1167 oauid=1001 ouid=0 oses=1 obj=unconfined ocomm="sleep"
      type=SYSCALL msg=audit(1677518008.586:237): arch=c000003e syscall=62 success=yes exit=0 a0=48f a1=9 a2=0 a3=7f61c64b2ac0 items=0 ppid=1034 pid=1035 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
      tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj=unconfined key="audit_kill"
      

データ収集スクリプトをデバッグする

次のスクリプトは、このページで説明するデバッグ タスクの多くを実行します。このスクリプトは、sudo モードまたは root モードで実行できます。このスクリプトは、システムからデバッグ情報のみを読み取ります。

$ cat kprot.sh
#!/bin/bash

echo "Boot command line"
cat /proc/cmdline
echo "=================================================="
echo "Loaded modules"
cat /proc/modules
echo "=================================================="
echo "Current tracer"
cat /sys/kernel/debug/tracing/current_tracer
echo "=================================================="
echo "Tracing event enable"
cat /sys/kernel/debug/tracing/events/enable
echo "=================================================="
echo "Tracing sub events enable"
for en in `find /sys/kernel/debug/tracing/events/*/enable`; do printf "\b$en\n"; cat $en; done
echo "=================================================="
echo "IP table rules"
iptables -L
echo "=================================================="
echo "Ftrace list"
cat /sys/kernel/debug/tracing/enabled_functions
echo "=================================================="
echo "Kprobes enabled"
cat /sys/kernel/debug/kprobes/enabled
echo "=================================================="
echo "Kprobes list"
cat /sys/kernel/debug/kprobes/list
echo "=================================================="
echo "Kprobes blocklist"
cat /sys/kernel/debug/kprobes/blacklist
echo "=================================================="
echo "BPF trace"
sudo apt update && sudo apt-get update && sudo apt-get install bpftrace
bpftrace -l
echo "=================================================="
echo "BPF prog list"
sudo apt update && sudo apt install linux-tools-`uname -r`
bpftool prog
echo "=================================================="

次のステップ