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 の組み込みサービスです。このサービスは、仮想マシンをスキャンして、侵害されたクラウド環境で実行されている、悪質な可能性のあるアプリケーション(暗号通貨マイニング ソフトウェア、カーネルモード ルートキット、マルウェアなど)を検出します。

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 メッセージを検索して、ツリー外モジュールが読み込まれたかどうかを確認できます。ログエントリでは、ツリー外モジュールは tainted 読み込みとしてマークされます。

カーネルログ バッファと 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 カーネルのドキュメントのライブパッチをご覧ください。

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 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
    

    ルートキットによって改ざんされることが多い 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. シグナルの監査ログエントリで詳細を確認します。この例では、この特定のシグナルはルートキットによって完全にハイジャックされていませんが、呼び出し元プロセスに関する情報は利用可能です。

      $ 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 "=================================================="

次のステップ