周一早上,运维打开后台发现所有 .jpg 变成了一串乱码后缀,首页弹出一张索要赎金的说明图;再登数据库,几张核心表的备注字段里塞满了同样的勒索文本。这不是电影桥段,而是近两年中小企业服务器最常见的安全事故之一。
本文只讨论防守与恢复视角:如何在第一时间止损、如何保全证据、如何从离线备份恢复业务、以及如何加固避免二次中招。关于攻击手法与勒索实现细节不在本文讨论范围内,因为了解这些对恢复业务毫无帮助。
先给结论:支付赎金不应被当作恢复方案。即便对方提供了解密密钥,也无法保证数据完整,且等于宣告你的系统是"愿意付钱的目标"。真正能把损失降到最低的,永远是你在此之前准备好的离线/不可变备份。
一、第一阶段:隔离(发现后 0-30 分钟)
隔离的目标只有一个:阻止影响继续扩散。不要急于分析,不要急于删除文件,先把口子堵上。
- 断开网络但不要关机。优先在云平台的安全组层面操作:把入站/出站规则改为全部拒绝,仅保留跳板机 IP 的访问。物理机则拔网线。不要关机——内存中可能保留着后续取证需要的信息。
- 隔离同网段其他主机。勒索软件通常会在内网横向移动,同 VLAN、同安全组的机器都要立即收紧策略,尤其是共享了 SMB/NFS 挂载的机器。
- 撤销所有凭据。立即轮换 SSH 密钥、数据库密码、云 API AccessKey、后台管理员口令。攻击者很可能已经掌握了凭据,只改被感染机器的密码是不够的。
- 冻结备份链路:立刻暂停正在运行的备份任务与
rsync同步,防止加密后的文件被同步覆盖掉备份端的旧副本。这一步最容易被忽略,也是最致命的一步。 - 截图与记录。对勒索提示页面、文件后缀、修改时间做截图记录,记录首个被加密文件的时间戳(这是判断入侵时间点的关键线索)。
# 1. 云平台安全组收紧后,本机再做一层(Linux,临时阻断除跳板机外的一切出站) iptables -I OUTPUT -d 10.0.0.0/8 -j DROP iptables -I OUTPUT -d 172.16.0.0/12 -j DROP iptables -I OUTPUT -d 192.168.0.0/16 -j DROP iptables -I INPUT -p tcp --dport 445 -j DROP iptables -I INPUT -p tcp --dport 2049 -j DROP # 2. 立刻停掉备份同步任务(防止加密文件覆盖备份) systemctl stop cron pkill -f 'rsync' ; pkill -f 'db_backup.sh' # 3. 卸载共享存储挂载点 umount -f /mnt/nfs-share 2>/dev/null || true umount -f /mnt/smb-share 2>/dev/null || true # 4. 记录当前进程、连接与计划任务(取证用) ps auxww > /root/incident/ps-$(date +%F-%H%M).txt ss -lntup > /root/incident/ss-$(date +%F-%H%M).txt crontab -l > /root/incident/cron-$(date +%F-%H%M).txt 2>&1 systemctl list-units --type=service --state=running > /root/incident/svc-$(date +%F-%H%M).txt
注意 pkill -f rsync 的时机:它必须在确认没有正在进行的正常备份任务时执行,否则可能把一次正常的备份打断。判断方法是先看 ps auxww | grep rsync 的输出,如果目标目录是备份服务器,立即终止;如果是从备份端往外拉,可以放它跑完。
二、第二阶段:取证与影响评估(30 分钟 - 4 小时)
取证的目的不是追查攻击者,而是回答三个工程问题:什么时候开始的、影响了哪些系统、备份是否还干净。这三个答案直接决定恢复策略。
2.1 确定加密起始时间点
# 找出最早被加密的文件(按修改时间排序,看异常后缀)
find /data -type f -newermt "7 days ago" \( -name "*.locked" -o -name "*.encrypted" -o -name "*.crypt" \) \
-printf '%T@ %p\n' | sort -n | head -20
# 查看系统近期登录记录
last -n 50
lastb -n 50 | head -30
journalctl -u sshd --since "14 days ago" | grep -iE "accepted|failed" | tail -50
# 检查新增的计划任务、服务与启动项
ls -la /etc/cron.d/ /var/spool/cron/crontabs/ 2>/dev/null
systemctl list-unit-files --state=enabled | grep -vE "@|dbus|sshd|cron|rsyslog|network"
# 检查近期被修改的可执行文件与脚本
find /usr/local/bin /opt /root -type f -mtime -14 -perm -u+x 2>/dev/null | head -30
2.2 判断备份是否可用(最关键的一步)
恢复的前提是备份本身未被加密。检查顺序如下:
- 离线/不可变备份:如果备份盘在备份完成后已
umount,或存储在开启了对象锁定(WORM)的对象存储中,这份备份是安全的,可直接用于恢复。 - 异地备份服务器:检查备份端的登录记录与文件时间戳。如果备份端从未暴露给生产网段(生产机只能
rsync写入、不能反向登录),通常也是安全的。 - 持续挂载的备份盘:如果备份目录一直在生产机上挂载且可写,那么它极可能已被加密,不能作为恢复源。
# 在备份端检查:是否有异常后缀文件、近期是否有异常登录 find /backup -type f -mtime -3 | head -20 ls -la /backup/mysql/ | tail -20 last -n 20 sha256sum -c /backup/mysql/2025-01-08.sha256 # 校验历史备份完整性
判断标准:只要有一份校验值通过、且时间戳早于加密起始时间的备份,就可以在不支付任何代价的前提下恢复业务。这正是 3-2-1 备份原则中"1 份离线/异地副本"的全部意义。
三、第三阶段:从离线备份恢复(4 小时 - 24 小时)
恢复必须遵循一个铁律:先重建干净环境,再导入数据,绝不原地覆盖。原地恢复会把残留的持久化机制一起带回来。
- 准备全新实例:用官方镜像创建全新云服务器,不要复用被感染实例的镜像或快照。
- 打全补丁并加固:完成系统更新、关闭不必要端口、配置密钥登录后再进行下一步。
- 导入数据:从离线/异地备份取回全量备份,必要时用 binlog 做时间点恢复,恢复到加密起始时间之前的时刻。
- 安全扫描:对恢复出来的数据做病毒扫描与内容检查,确认没有夹带恶意脚本(尤其是上传目录、文章内容、模板文件)。
- 切换流量:修改 DNS 或负载均衡指向新实例,保留旧实例关机但不销毁,用于后续取证。
- 持续观察:切换后 72 小时内加密监控告警,确认没有二次感染迹象。
# 在全新实例上恢复 MySQL(先全量,再 binlog 回放到事故前)
zcat /backup/mysql/all-2025-01-08.sql.gz | mysql -u root -p
mysqlbinlog --start-position=157 --stop-datetime="2025-01-10 03:00:00" \
/backup/binlog/mysql-bin.00012{0,1,2} | mysql -u root -p
# 恢复站点文件(用 rsync --link-dest 的历史快照,取事故前版本)
rsync -a --dry-run /backup/www/2025-01-09-0200/ /var/www/html/
rsync -a /backup/www/2025-01-09-0200/ /var/www/html/
# 恢复后对上传目录做安全扫描
clamscan -r --infected --remove=no /var/www/html/uploads/
grep -rIl "eval(" /var/www/html/ | head -20
# 校验恢复结果
sha256sum -c /backup/mysql/2025-01-08.sha256
mysql -e "SELECT COUNT(*), MAX(created_at) FROM appdb.orders;"
时间点选择的原则:恢复目标时刻必须早于最早被加密文件的时间戳,并留出足够安全边界。如果最早加密时间是 03:20,建议恢复到前一天 02:00 的备份点,而不是当天 03:19——因为入侵往往远早于加密动作发生。
四、第四阶段:加固(恢复后持续进行)
业务恢复不等于事件结束。若不加固,同样的路径会被再次利用。
4.1 入口收敛
# SSH:禁用密码登录、禁用 root 直登、限制可登录用户 # /etc/ssh/sshd_config # PermitRootLogin no # PasswordAuthentication no # PubkeyAuthentication yes # AllowUsers opsadmin backup systemctl restart sshd # 防火墙只放行必要端口 ufw default deny incoming ufw allow from 10.0.0.0/8 to any port 22 ufw allow 80/tcp ufw allow 443/tcp ufw enable # 关闭并禁用不必要的文件共享服务 systemctl disable --now smbd nmbd nfs-server 2>/dev/null || true ss -lntp | grep -E "445|139|2049" || echo "no file-sharing ports"
4.2 权限与凭据治理
- 所有服务使用非 root 专用账号运行,数据库账号按库授权,禁止
ALL PRIVILEGES ON *.*。 - 云 API 子账号最小权限,AccessKey 定期轮换,禁止把 AK 写进代码或镜像。
- 开启多因素认证(MFA),尤其是云控制台与远程桌面/VPN 入口。
- 禁用长期有效的共享账号,改为一人一号 + 堡垒机审计。
4.3 备份体系加固(最重要)
这次事件暴露的最大问题通常是:备份与生产在同一信任域内。加固方案:
| 措施 | 实现方式 | 抵御的场景 | 成本 |
|---|---|---|---|
| 离线卸载 | 备份完成后 umount 备份盘 | 生产机被加密 | 极低 |
| 单向推送 | 生产机只能写入备份端,备份端禁止反向登录 | 凭据泄露后横向移动 | 低 |
| 对象锁定 WORM | 对象存储开启合规保留期 | 凭据泄露后删除备份 | 中 |
| 多版本保留 | rsync --link-dest 保留 30 个历史版本 | 加密发生后才被发现 | 低 |
| 校验值留存 | sha256sum 与备份分离存放 | 静默损坏 | 极低 |
# 单向推送 + 受限密钥:备份端 authorized_keys 前缀
# command="/usr/local/bin/rrsync -wo /backup/mysql/",no-pty,no-agent-forwarding,restrict ssh-ed25519 AAAA... backup
# 备份完成后卸载备份盘(离线化)
rsync -a --link-dest=/backup/www/2025-01-09-0200/ /var/www/html/ /backup/www/2025-01-10-0200/
umount /backup
# 下次备份前再 mount,脚本中成对出现
# 定期校验历史备份
sha256sum -c /backup/mysql/$(date +%F).sha256
find /backup -name "*.sha256" -mtime -1 -exec sha256sum -c {} \; >> /var/log/backup_verify.log
4.4 监测与响应机制
- 部署主机入侵检测(HIDS)与文件完整性监控,对
/etc、/usr/local/bin、站点目录的批量修改行为告警。 - 把"短时间内大量文件被重命名/修改"设为独立告警规则,这是最接近勒索行为的特征。
- 日志集中化存储到独立服务器,避免攻击者在本机清理日志。
- 制定并演练事件响应预案,明确隔离决策人、取证负责人、对外沟通口径。
五、事件后的复盘要点
- 入侵路径是什么(弱口令、未修复漏洞、泄露的密钥、被攻陷的第三方组件)?
- 从入侵到加密之间间隔多久?监控为什么没有发现?
- 实际 RPO 与 RTO 各是多少?与预案目标差多少?
- 备份是否可用?如果不可用,具体是哪一个环节失效?
- 哪些加固措施可以自动化,避免依赖人工纪律?
小结
服务器遭遇勒索软件时的处置链条是固定的四步:隔离 → 取证 → 从离线备份恢复 → 加固。其中隔离阶段最关键的两个动作是撤销所有凭据与立即冻结备份同步;取证阶段的核心是确定加密起始时间点并判断备份是否干净;恢复阶段必须在全新实例上进行,绝不原地覆盖;加固阶段的重点是把备份体系移出生产的信任域。
避坑清单
- 发现后立即暂停备份任务与 rsync 同步,否则加密文件会覆盖掉备份端的旧副本。
- 不要关机,内存中可能保留取证所需信息;采用网络层隔离。
- 不要只改被感染机器的密码——所有凭据(SSH 密钥、AK、数据库口令)都要轮换。
- 持续挂载可写的备份盘不能作为恢复源,它可能已被加密。
- 恢复目标时刻要留出安全边界,不要卡在加密前一分钟。
- 旧实例关机但不要销毁,保留取证材料。
- 恢复后必须扫描上传目录与模板文件,防止夹带恶意脚本。
- 支付赎金不是恢复方案,也无法保证数据完整。
企业QQ咨询




