服务器被 Mirai 木马入侵:一次完整的应急响应实录

服务器被 Mirai 木马入侵:一次完整的应急响应实录

作为独立开发者(一人公司),我的云服务器被 Mirai 僵尸网络木马入侵。本文记录了从发现告警、溯源分析、应急清理到安全加固的完整过程,希望能为同样使用云服务器的开发者提供一份实用的安全参考。


一、事件发现

腾讯云安全中心弹出了一条高危告警:

  • 病毒类型: Linux.Backdoor.Agent.Ssmw(Mirai 变种)
  • 恶意行为: wget 正从外部 IP(84.247.128.162)下载名为 rbot 的恶意文件到项目目录 /root/projects/flower-shop/apps/server/
  • 攻击目的: 将服务器加入僵尸网络,用于发起 DDoS 攻击或扫描其他设备

关键线索: 恶意文件被直接下载到 /root 目录下,说明攻击者已获取系统最高权限。


二、入侵路径分析

Mirai 木马的典型入侵方式有以下几种。结合我服务器的实际情况,逐一排查:

1. 弱口令 / SSH 暴力破解

Mirai 通过扫描弱密码感染设备。如果 SSH 使用默认 22 端口 + 简单密码,自动化脚本几秒内就能暴力破解。

我的密码强度实际上不低,所以这不一定是唯一入口。但密码登录本身就是风险敞口。

2. 暴露的端口与服务

除了 SSH,如果还运行了 Redis、MySQL 或 Node.js 应用等服务,且存在未授权访问或已知漏洞,攻击者可以借此突破。

3. 应用层漏洞(RCE)

如果 Web 应用代码中存在文件上传漏洞或命令注入漏洞,攻击者可以直接通过应用执行 wget 下载木马,然后利用本地提权获取 root 权限。

4. 即使密码复杂,也可能被窃取的几种途径

  • SSH 私钥泄露: 私钥保存在不安全的地方,或本地开发机中了马
  • 应用层 RCE: 攻击者通过 Web 漏洞进来,不需要密码
  • 侧向渗透: 同一台服务器上某个旧服务(如未授权的 Redis / Docker API)存在漏洞,攻击者从一个"窗户"爬进来后横向移动

三、入侵痕迹取证

3.1 定时任务中的"定时炸弹"

执行 crontab -l 发现了一条恶意持久化指令:

@reboot /root/.config/sys-update-daemon -name shop.laohuoji.link >/dev/null 2>&1

这条指令的特征:

特征 说明
伪装性 文件名伪装成系统更新守护进程 sys-update-daemon,藏在隐藏目录 .config
持久化 @reboot 意味着每次重启服务器都会自动启动木马
定向标记 域名 shop.laohuoji.link 说明攻击者对目标做了标记

3.2 Git 状态异常——文件权限被批量篡改

在服务器上执行 git status,发现大量核心配置文件被标记为 modified

modified:   README.md
modified:   components.json
modified:   ecosystem.config.js
modified:   next.config.mjs
modified:   package.json
modified:   pnpm-lock.yaml
modified:   postcss.config.mjs
modified:   tailwind.config.js
modified:   tsconfig.json
modified:   update-admin-password.mjs

通过 git diff 排查发现:代码内容并未被修改,但文件权限从 644(普通文件)被改为 755(可执行)。

diff --git a/apps/server/package.json b/apps/server/package.json
old mode 100644
new mode 100755

推测原因: 攻击者在批量执行 chmod +x 时,把整个项目目录的文件都改成了可执行权限,以便恶意程序能顺利运行。

3.3 /tmp 目录中的可疑残留

find /tmp -type f

发现以下异常文件:

  • 高度可疑 — 以 MD5 字符串为目录名的 sw.js 文件(共 4 个),疑似是攻击者用于 Web 劫持的 Service Worker 残留
  • 异常文件/tmp/ac3ebce8/tmp/bc7078b6,随机 8 位文件名、无后缀,通常是恶意程序的临时指令文件

3.4 ZSH 历史记录——还原"行军路线"

通过 tail -n 200 ~/.zsh_history 分析:

  • 历史中没有任何用户主动下载 rbot 或设置 sys-update-daemon 的指令
  • rbot 进程以 root 权限在后台运行,确认为外部注入而非误操作
  • 发现 pnpm-lock.yaml 也曾被篡改,可能是攻击者尝试供应链攻击(诱导 pnpm install 时下载带后门的依赖包)

3.5 网络连接审计

netstat -antp | grep ESTABLISHED

结果显示所有连接均为正常服务:

  • tat_agent / YDService:腾讯云自带的监控服务(内网地址 169.254.x.x
  • sshd: root@:当前操作者的 SSH 连接

结论:没有可疑的外联 IP,隐藏后门已被清除。


四、应急处理步骤

第一步:阻断攻击入口

  1. 修改 SSH 配置,关闭密码登录,强制使用密钥:
    vim /etc/ssh/sshd_config
    # 设置以下两项:
    # PasswordAuthentication no
    # PubkeyAuthentication yes
    systemctl restart sshd
    
  2. 检查 authorized_keys,确保只有自己的公钥:
    cat /root/.ssh/authorized_keys
    

第二步:清除持久化后门

  1. 删除恶意定时任务:
    crontab -e
    # 删除包含 @reboot ... sys-update-daemon 的那一行
    # 保留腾讯云监控 stargate 的那行
    
  2. 杀死恶意进程并删除文件:
    pkill -f sys-update-daemon
    rm -rf /root/.config/sys-update-daemon
    rm -f /root/projects/flower-shop/apps/server/rbot
    

第三步:恢复代码完整性

  1. 利用 Git 强制回滚,重置所有文件权限和内容:
    git reset --hard HEAD
    git clean -fd
    
  2. 确认 git status 显示 working tree clean

第四步:清理临时文件

rm -rf /tmp/*sw.js
rm -f /tmp/ac3ebce8 /tmp/bc7078b6
rm -rf /tmp/84eaac9ce9f32b023dfa052d9f13ff03*

第五步:重新部署项目(最彻底方案)

rm -rf flower-shop
git clone git@github.com:dohard-ma/flower-shop.git
cd flower-shop/apps/server
pnpm i

原则: 既然已经被入侵,与其一个文件夹一个文件夹检查,不如直接删除项目目录重新 clone 干净代码。如果条件允许,直接重装系统是最稳妥的选择。


五、事后加固:建立监控预警

为了防止类似事件再次发生且不被发现,我用一个简单的 Shell 脚本 + 飞书 Webhook 搭建了自动巡检:

监控脚本 ~/scripts/monitor_project.sh

#!/bin/bash

# --- 配置区 ---
PROJECT_DIR="/root/projects/flower-shop"
WEBHOOK_URL="你的飞书/钉钉 Webhook 地址"
SERVER_NAME="生产服务器"

# --- 执行检查 ---
cd $PROJECT_DIR

# 1. 检查未追踪文件(排除 logs)
UNTRACKED=$(git ls-files --others --exclude-standard | grep -v "logs/")

# 2. 检查已追踪文件是否被篡改
MODIFIED=$(git diff --name-only)

if [ ! -z "$UNTRACKED" ] || [ ! -z "$MODIFIED" ]; then
    REPORT=""
    [ ! -z "$MODIFIED" ] && REPORT="$REPORT\n[被篡改文件]:\n$MODIFIED"
    [ ! -z "$UNTRACKED" ] && REPORT="$REPORT\n[新文件]:\n$UNTRACKED"

    MESSAGE="⚠️ 安全预警:[$SERVER_NAME] 发现代码变动!$REPORT"

    # 使用 python3 处理 JSON 转义(避免换行符破坏 JSON 结构)
    SAFE_MESSAGE=$(printf '%s' "$MESSAGE" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')

    curl -X POST -H "Content-Type: application/json" \
    -d "{
        \"msg_type\": \"text\",
        \"content\": {
            \"text\": $SAFE_MESSAGE
        }
    }" $WEBHOOK_URL
fi

设置定时巡检

crontab -e
# 添加以下内容,每小时检查一次:
0 * * * * /bin/bash /root/scripts/monitor_project.sh > /dev/null 2>&1

踩坑记录: 飞书 Webhook 对 JSON 格式要求严格。直接在 curl -d 中拼接含换行符的字符串会导致 Bad Request。解决方案是用 python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))' 对消息内容做 JSON 安全转义。


六、经验总结

安全清单(独立开发者必做)

优先级 措施 说明
🔴 P0 禁用 SSH 密码登录 设置 PasswordAuthentication no,强制密钥登录。这是防御 Mirai 等僵尸网络最有效的手段
🔴 P0 修改 SSH 默认端口 弃用 22 端口,改为 10000 以上的随机端口
🔴 P0 配置安全组 在云控制台中,仅允许常用 IP 访问 SSH 端口
🟡 P1 定期审计 authorized_keys 确保只有自己的公钥,防止攻击者植入后门密钥
🟡 P1 检查应用层漏洞 排查代码中是否有 exec()spawn() 等直接调用系统命令的地方
🟡 P1 确认 .env 不泄露 .env 必须在 .gitignore 中,不通过 Nginx 被公开访问
🟢 P2 建立自动巡检 通过 cron + Webhook 监控代码变动
🟢 P2 定期清理 每隔几个月执行 git clean -fd 确保无外部残留

核心原则

  1. 重装优于修补 — 系统被 root 入侵后,简单删除文件无法保证安全。攻击者可能已修改系统二进制文件(如 lsps)来隐藏自己。最稳妥的方案是备份数据后重装 OS。

  2. 不要信任密码 — 无论密码多复杂,SSH 密钥登录才是终极防线。

  3. Git 是最好的入侵检测器 — 生产服务器上保持 working tree clean 状态,任何变动都可能是入侵信号。

  4. /tmp 是攻击者的乐园 — 攻击者喜欢在 /tmp/var/tmp/dev/shm 等目录存放临时脚本,定期检查这些位置。

  5. 密钥泄露比暴力破解更常见 — 高强度密码也挡不住 RCE 攻击或内网渗透,从源头封死入口才是根本。


附录:关键排查命令速查

# 查看定时任务
crontab -l

# 查看系统级定时任务
ls -la /etc/cron.d/
ls -la /etc/cron.daily/
cat /etc/crontab

# 查找可疑文件
find /tmp -type f
find /var/tmp -type f

# 检查当前网络连接
netstat -antp | grep ESTABLISHED

# 查看 Git 文件变动
git status
git diff --name-only

# 杀死可疑进程
ps -ef | grep <关键词>
pkill -f <进程名>

# Git 强制回滚
git reset --hard HEAD
git clean -fd