午前2時14分のインシデント:現実を突きつけられる瞬間
午前2時14分。ページャーが鳴り響く。監視ダッシュボードには、主要なWebクラスター全体でCPU使用率が95%に急上昇していることが示されている。SSHでログインしてtopを実行すると、十数個のPHP-FPMプロセスが利用可能なサイクルを奪い合っている。最初の直感はトラフィックの急増だが、netstatを実行すると、既知の悪意のあるIP範囲への異常なアウトバウンド接続が明らかになる。これはバイラルな投稿によるものではない。現在進行形の侵害だ。
CLIフォレンジックを「デジタルな追跡」と考えてください。嵐が吹き荒れる中で、地面に残された足跡を探しているのです。これらの手動スキルを習得することこそが、単に運用手順書に従うだけの人と、シニアエンジニアを分かつ境界線となります。
真実の源:生のログ vs 自動化ツール
調査中、通常は自動化されたセキュリティスイート(WAF、IDS、SIEM)か、手動のCLI分析のどちらかを選択することになります。
- 自動化ツール(WAF/SIEM): これらはリアルタイムのブロックに優れています。シグネチャを使用して、
<script>alert(1)</script>のような明白なパターンにフラグを立てます。しかし、巧妙なエンコーディングやカスタムのゼロデイペイロードによってバイパスされる可能性があります。 - 手動CLI分析: これが「真実の源(Ground Truth)」です。
grep、awk、sed、uniqといった標準的な Linux ユーティリティを使用してデータを切り分けます。高速で、生で、編集されていない情報が得られます。
ModSecurityのようなWAFは第一防衛線ですが、手動フォレンジックは事後分析のための「メス」となります。なぜフィルターをすり抜けたのか? 攻撃者は正規表現を回避するために16進エンコーディングを使用したのか? 生のログだけが、フィルターを通さない一連の出来事を提供してくれます。
ターミナルで作業を完結させるメリットとデメリット
メリット
- ポータビリティ: 地球上のあらゆるLinuxマシンには
grepが備わっています。追跡を開始する前に、5GBのログファイルが中央サーバーにアップロードされるのを待つ必要はありません。 - ゼロ遅延: ロギングパイプラインの取り込み遅延をバイパスし、リクエストがディスクに書き込まれた瞬間にその内容を確認できます。
- 無限の柔軟性: 標準的なシグネチャが見逃した難読化された攻撃を捉えるために、複雑でネストされた正規表現をその場で作成できます。
デメリット
- 人的ミスの余地: 正規表現のタイポ一つが、偽陰性(見逃し)につながる可能性があります。精度がすべてです。
- 学習曲線の険しさ: HTTPステータスコードや、一般的な攻撃ペイロードがURLエンコードされた際にどのように見えるかを理解している必要があります。
- 視覚的な疲労: 黒背景に白文字のテキストを何千行も見続けると、グラフなら瞬時に強調されるような、量に基づく異常を見落としやすくなります。
設定:視界不良で飛ばないために
記録されていないものを追跡することはできません。NginxやApacheのログがIPアドレスとURLしか追跡していない場合、ストーリーの半分を見逃しています。最低限、「Combined」ログフォーマットを使用してください。さらに良いのは、特定のエンドポイント(ログインページを除く)に対して$request_bodyを含め、$http_user_agentが常にログに記録されるようにすることです。
ログのローテーションによって証拠が消えないようにしてください。侵害の最中には、最初の調査を見つけるために48時間または72時間遡る必要があることがよくあります。サーバーが高負荷な場合は、フォレンジック操作がOSのI/Oサイクルを奪わないよう、ログを別のディスクパーティションにパイプすることを検討してください。
実装ガイド:攻撃者を追跡する
1. SQLインジェクション(SQLi)の検出
SQLインジェクションは、依然としてデータベースをダンプするための最も効率的な方法です。攻撃者は、UNION SELECTやGROUP_CONCATのようなコマンドを注入できる脆弱なGETパラメータを探します。同じURLに対して、少しずつ異なるSQLキーワードを含む20のリクエストが連続して見られる場合、それは調査(プローブ)を発見したことになります。
以下のコマンドで不審なGETリクエストを検索します。
grep -iE "(select|union|concat|order\s+by|group_concat|information_schema)" /var/log/nginx/access.log
巧妙な攻撃者は、URLエンコーディングを使用して基本的なフィルターを回避します。彼らは ' を %27 に、スペースを %20 に置き換えます。ターミナルビューでこれらの文字をデコードするためにsedを使用すると、パターンが明確になります。
grep -iE "(%27|%22|%3B|%2D%2D)" /var/log/nginx/access.log | sed -e 's/%27/'\''/g' -e 's/%20/ /g'
インジェクションの成功(404が期待される場所で200 OKレスポンスが返っているなど)を確認したら、最優先事項は認証情報のローテーションです。私は新しいサーバーのシークレット作成に、toolcraft.app/ja/tools/security/password-generator のパスワードジェネレーターを使用しています。これは完全にブラウザ内で動作するため、自身のネットワーク環境が信頼できない場合に不可欠です。
2. 隠れたWebシェルの暴露
Webシェルは、攻撃者に持続的なアクセス権を与えるバックドアスクリプト(.phpや.aspxなど)です。彼らがそれにshell.phpという名前を付けることは稀です。代わりに、legacy_backup.phpのような名前に偽装されたり、/uploads/ディレクトリ内に隠されたりします。
Webシェルの一般的な「兆候」は、データを送るべきではないファイルに対するPOSTリクエストです。awkを使用してPOSTターゲットをリストし、頻度順に並べ替えます。
awk '$6 == "\"POST" {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr
外れ値を探してください。もしcontact.phpに500件のPOSTがあれば、それは正常です。しかし、assets/js/theme-min.phpに12件のPOSTがあるなら、それはシェルの可能性が高いです。また、curlやpython-requestsのような、空または一般的なUser-Agentを持つリクエストも確認してください。
awk -F'"' '$6 == "-" {print $1, $2, $4}' /var/log/nginx/access.log
3. 持続性とアウトバウンドの動き
シェルを設置すると、攻撃者はしばしばlinpeas.shのようなポストエクスプロイトツールをダウンロードします。外部IPアドレスに関連付けられた200ステータスコードをログで確認してください。攻撃者が賢ければ、www-dataユーザーの.bash_historyを即座に消去するため、それだけに頼らないようにしましょう。
findを使用して、過去24時間以内にWebルート内で変更されたすべてのファイルを特定します。
find /var/www/html -mtime -1 -ls
これらのタイムスタンプをアクセスログと照らし合わせます。これらのファイルが作成された直後に誰がアクセスしたか? どのようなパラメータが渡されたか? ログがそれを教えてくれます。
隙間を埋める
フォレンジックは単に侵入者を見つけることだけではなく、開けっ放しになったドアを特定することでもあります。Webシェルを見つけたら、その作成に至るまでの10分間のログを確認してください。脆弱なプラグインや認証のないアップロードフォームへのPOSTリクエストが見つかるはずです。
CLIでの深掘りは骨の折れる作業ですが、何が「正常」であるかのメンタルモデルを構築してくれます。これにより、次に午前2時にページャーが鳴り響いたとき、「異常」を特定するのがずっと簡単になります。ツールを研ぎ澄まし、ログを詳細に記録し、パスワードをユニークに保ちましょう。

