TT Lab
はじめる
学ぶ 学習パス コース

cron が午前三時に curl を叩いた

残る場所と残らない場所を切り分ける

TT Labで続きを見る

このラボはVM上で動きます

Ubuntu 24.04のVMが1台です。rootで、カーネル権限があるので、監査ルールを実際にロードできます。ラボのPodにはcapabilityが1つもなく、auditctlがまったく動作しないため、このラボだけがVMで動きます。最初に立ち上がるのに、1–2分かかります。

目標

カーネル監査ルールを自分でかけ、イベントをわざと発生させ、その記録を取り出して読みます。同じイベントをジャーナル側でもう一度探して、2つの記録がそれぞれ何を持っているかを見て、最後に監視していない場所を見つけて、それを覆います。

なぜ重要なのか

検知ルールを書く前に答えるべき問いがあります。そのイベントが、そもそもどこかに記録されるか。Linuxでは、カーネル監査は、既定ではほとんど何も残しません。ルールをかけたパスとシステムコールだけを見ます。そのため、「ログはすべて集めているのに、答えがない」という状況が生まれます。

ここで学ぶのはコマンドではなく、範囲の感覚です。自分のルールが何を見て何を見ないのかを言えれば、インシデントが起きたときに、「記録がない」と「その場所を見ていなかった」を区別できます。この2つは、まったく別の処方につながります。

ステップ

  1. auditctl -sとサービスの状態を保存してください(保存先: /root/det/01-status.txt)。
  2. /etc/cron.dを書き込みと属性変更について監視するルールを、キーcron_changeで書き(書き込み先: /etc/audit/rules.d/labhub.rules)、カーネルにロードしてください。
  3. 64ビットのexecveのうち、実行ファイルが/usr/bin/curlのものだけを捕まえるルールを、キーoutbound_execで同じファイルに追加し、ロードしてください。
  4. curlを呼び出すcronファイル(/etc/cron.d/nightly-report)を作成し、curlを手で1回実行したあと、何をしたかを保存してください(保存先: /root/det/04-trigger.txt)。
  5. ausearch -k outbound_exec -iの最後のイベントを保存し(保存先: /root/det/05-evidence.txt)、その下にpid=・exe=・key=の3つの値を書いてください。
  6. ジャーナルからcronの実行記録をJSONで取り出して保存してください(保存先: /root/det/06-cron.json)。このVMで毎分動く作業(labhub-metrics)の実行行が入っている必要があります。
  7. 実行ビットを与えたスクリプト(/usr/local/bin/labhub-helper.sh)を作成し、cron_changeキーではその記録が残らないことを確認して、コマンド・結果・理由を書いてください(保存先: /root/det/07-blindspot.txt)。
  8. /usr/local/binをキーpersistenceで監視するルールを追加してロードし、ファイルをもう一度直して、記録が残ることを確認してください(確認結果の保存先: /root/det/08-closed.txt)。
  9. このホストの検知範囲を、## 무엇이 남는가・## 무엇이 남지 않는가・## 규칙 목록・## 다음에 할 일(韓国語の見出しで、順に「何が残るのか」「何が残らないのか」「ルールの一覧」「次にすること」という意味です)の4つの節で書いてください(保存先: /root/det/09-report.md)。

参考

何が有効になっているか

auditctl -sの出力とsystemctl is-active auditdの結果を保存してください(保存先: /root/det/01-status.txt)。enabledとbacklog_limitの値が、そのまま入っている必要があります。

auditctl -sは、カーネル監査サブシステムの現在の状態を、1行ずつ出します。2つのコマンドの出力を、1つのファイルに連結すればよいです。

スケジュールされたジョブのディレクトリを監視する

/etc/cron.dを書き込み(w)と属性変更(a)について監視し、キーをcron_changeとして付けるルールを書き(書き込み先: /etc/audit/rules.d/labhub.rules)、カーネルにロードしてください。

ファイル監視ルールは、-w <경로> -p <권한> -k <키>の形です(プレースホルダーはパス、権限、キーです)。rules.dに書いたものをカーネルにロードするコマンドはaugenrules --loadで、ロードされたルールはauditctl -lで確認します。

何が実行されたのか

64ビットのexecveのうち、実行ファイルが/usr/bin/curlのものだけを捕まえるルールを、キーoutbound_execで同じファイルに追加し(追加先: /etc/audit/rules.d/labhub.rules)、カーネルにロードしてください。

システムコールルールは、-a always,exit -F arch=b64 -S <시스콜> -F <필터> -k <키>の形です(プレースホルダーはシステムコール、フィルター、キーです)。実行ファイルのパスで絞り込むフィルター名はexeです。ファイル監視では、「何が実行されたのか」が見えません。

イベントを発生させる

午前3時にcurlを呼び出すcronファイル(/etc/cron.d/nightly-report)を作成し、続けてcurlを手で1回実行してください。そして、何をしたかを2行以上で書いてください(保存先: /root/det/04-trigger.txt)。

ルールをロードしたあとにファイルを作らないと、記録が残りません。curlは実際にどこかに届く必要はありません。実行されたという事実が、execveとして残ります。

記録を取り出して読む

ausearch -k outbound_exec -iの最後のイベントを保存し(保存先: /root/det/05-evidence.txt)、その下にpid=・exe=・key=の3つの値を、それぞれ1行で書いてください。

-iを外すと、uidとシステムコール番号が数字で出ます。最後のイベントだけを見るには、ausearchの結果をawk/sedで、最後の----区切りのあとだけを残すか、tailで切り取ればよいです。

同じイベントをジャーナルで

ジャーナルからcronが残した実行記録をJSONで取り出して保存してください(保存先: /root/det/06-cron.json)。このVMで毎分動く作業(labhub-metrics)のCMD行が入っている必要があります。

journalctl -t CRON -o json --since "-30 min"なら、1行に1つずつJSONが出ます。まだ動いていなければ、1分待ってからもう一度取り出してください。

監視していない場所

実行ビットを与えたスクリプト(/usr/local/bin/labhub-helper.sh)を作成し、ausearch -k cron_changeにそのパスが出てこないことを確認して、コマンド・結果・なぜ残らないのかを、120文字以上で書いてください(保存先: /root/det/07-blindspot.txt)。

監査ルールは、書いておいたパスだけを見ます。攻撃者は、スケジュールされたジョブを新しく作る必要がなく、すでにスケジュールされたスクリプトの内容を直せばよいのです。その場所が今、監視の外にあることを、自分で確認するステップです。

空いている場所を覆う

/usr/local/binを書き込み・属性変更について監視するルールを、/etc/audit/rules.d/labhub.rulesに追加してロードしてください。付けるキー: persistence。そして、labhub-helper.shをもう一度直して、記録が残ることを確認してください(確認結果の保存先: /root/det/08-closed.txt)。

キーをcron_changeにすると、ステップ7で確認した「残らない」がひっくり返り、前のステップが壊れます。新しい場所は、新しいキーで覆います。ルールをロードしたあとに、ファイルを直さないと、記録が残りません。

検知範囲を文書にする

このホストで今、何が残り、何が残らないのかを、## 무엇이 남는가・## 무엇이 남지 않는가・## 규칙 목록・## 다음에 할 일(韓国語の見出しで、順に「何が残るのか」「何が残らないのか」「ルールの一覧」「次にすること」という意味です)の4つの節で書いてください(保存先: /root/det/09-report.md)。3つのキーの名前と、ルールファイルのパスが、本文に出てくる必要があります。

ルール一覧の節には、auditctl -lの結果を貼れば十分です。「何が残らないのか」が、この文書で最も価値のある節です。次の人が「すべて残る」と信じないようにしてくれる場所です。