Linux下rm-rf误删文件后,我们是如何完成数据恢复的

admin 2026-06-26 06:48:21 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文通过真实案例复盘Linux服务器因rm-rf误删备份数据的应急响应全流程,详细阐述立即停止写入、状态记录、工具恢复等关键步骤,深入解析ext4/xfs文件系统删除原理与恢复局限,并提供extundelete、debugfs等工具实操方法及防误删工程实践建议。 综合评分: 87 文章分类: 应急响应,数据安全,系统安全,安全工具,安全运营


10.4 适合 photorec 的场景

  • 文件类型多样(图片、文档、视频)
  • 文件数量少(几十到几百个)
  • FS 元数据完全损坏
  • 最后兜底

对于备份服务器里几百 GB 的 mysqldump SQL 文件,photorec 不太合适——它会把每个 block 切碎然后按特征匹配,SQL 文件内部有大量重复模式,容易被切碎。


11. 方案 E:lsof 抢救未关闭文件(成本最低的恢复)

前面 5.4 节已经提过,这里展开讲。这是最容易成功、风险最低、速度最快的恢复方式。

11.1 找到 deleted but still open 的文件

# 列出所有 deleted 文件
lsof | grep deleted

输出示例(注意:不同 lsof 版本会显示或不显示 TID 列):

mysqld  1234  1234  mysql  8u  REG  253,1  104857600  12345  /data/backup/mysql/dump_20260608.sql (deleted)
rsync   5678  5678  root   3r  REG  253,1   52428800  12346  /data/backup/app/app-20260608.tar.gz (deleted)

其中:

  • 第 5 列:FD(含访问模式字母,如 8u 表示 FD=8 的 u=read+write)
  • 第 7 列:文件大小(字节)
  • 第 8 列:inode 号
  • 第 9 列:原始路径 + (deleted) 标记

为什么推荐 lsof -F 解析:手工数列数(awk $2awk $4)在 TID 列存在与否的两种 lsof 输出下表现不同,新人最容易在这里翻车。下面 11.3 的脚本用 -F 规避这个问题。

11.2 恢复单个文件

# 把 1234 进程的第 8 个 fd 复制出来
cp /proc/1234/fd/8 /tmp/recovered_dump_20260608.sql

# 验证大小
ls -la /tmp/recovered_dump_20260608.sql
# 应该跟 deleted 文件的大小一致

11.3 批量恢复脚本

#!/bin/bash
# recover_deleted.sh
# 恢复所有 deleted 但被进程持有的文件
# 用法:./recover_deleted.sh /mnt/recovery
#
# 说明:使用 lsof -F 输出(每行一个键值对)规避 awk 字段数随版本
#      变化(TID 列有时存在有时缺失)的问题。
# &nbsp; &nbsp; &nbsp;p=<PID> &nbsp;f=<FD> &nbsp;n=<NAME> 是我们关心的三种字段

OUT_DIR="${1:-/tmp/recovered}"
mkdir -p&nbsp;"$OUT_DIR"

# 1. 抓出所有 deleted 文件
# &nbsp; &nbsp;-F pfn: &nbsp;仅输出 p/f/n 三个字段
# &nbsp; &nbsp;2>/dev/null: 忽略 lsof 因权限不足输出的部分 warning
lsof -F pfn 2>/dev/null > /tmp/lsof_f.txt

# 2. 解析:把 p/f/n 三行组合成一条记录
awk -v OUT_DIR="$OUT_DIR"'
/^p/ {
&nbsp; &nbsp; pid = substr($0, 2)
&nbsp; &nbsp; fd = ""
&nbsp; &nbsp; name = ""
&nbsp; &nbsp; deleted = 0
&nbsp; &nbsp; next
}
/^f/ {
&nbsp; &nbsp; fd = substr($0, 2)
&nbsp; &nbsp; next
}
/^n/ {
&nbsp; &nbsp; name = substr($0, 2)
&nbsp; &nbsp; if (name ~ / \(deleted\)$/) {
&nbsp; &nbsp; &nbsp; &nbsp; deleted = 1
&nbsp; &nbsp; &nbsp; &nbsp; # 去掉 " (deleted)" 标记
&nbsp; &nbsp; &nbsp; &nbsp; name = substr(name, 1, length(name) - 10)
&nbsp; &nbsp; }
}
{
&nbsp; &nbsp; if (deleted && pid != "" && fd != "" && name != "") {
&nbsp; &nbsp; &nbsp; &nbsp; # 构造目标文件名:pid_fd_原路径
&nbsp; &nbsp; &nbsp; &nbsp; safe = name
&nbsp; &nbsp; &nbsp; &nbsp; gsub(/\//, "_", safe)
&nbsp; &nbsp; &nbsp; &nbsp; target = OUT_DIR "/" pid "_" fd "_" safe

&nbsp; &nbsp; &nbsp; &nbsp; # 调用 cp 复制
&nbsp; &nbsp; &nbsp; &nbsp; cmd = "cp -a /proc/" pid "/fd/" fd " \"" target "\" 2>/dev/null"
&nbsp; &nbsp; &nbsp; &nbsp; if (system(cmd) == 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print "RECOVERED: " name " -> " target
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; deleted = 0
&nbsp; &nbsp; }
}
'&nbsp;/tmp/lsof_f.txt

rm -f /tmp/lsof_f.txt

使用:

chmod +x recover_deleted.sh
./recover_deleted.sh /mnt/recovery

风险提示:

  • 这个脚本会触发对 /proc/$pid/fd/$fd 的访问,可能短暂占用 fd
  • 对每个进程有权限要求,root 才能访问其他用户的 fd
  • 不要在生产业务机上跑,先演练
  • lsof -F 的输出里 NAME 可能包含空格,脚本里的 cp 已加引号兜底
  • 如果 lsof 版本过老不支持 -F,可改用 lsof +c 0 -P -n 加手工解析

11.4 实战中的几个问题

Q:进程是 root 启动的,但文件实际属于 mysql 用户,能恢复吗?

A:能。内核只校验调用进程的权限,root 可以访问任何 fd。

Q:lsof 输出里有 deleted 文件,但 /proc/$pid/fd 路径不存在?

A:可能进程已经退出了。lsof 是当时的状态,进程退出后 /proc/$pid 整个消失。

Q:lsof 输出里有 N 个 deleted,但我用上面的脚本只恢复了 M 个(M < N)?

A:可能某些 fd 已经被进程关闭但还没被内核回收。增加睡眠重试,或者直接按 inode 扫。


12. 方案 F:LVM / ZFS / btrfs 快照回滚(成功率最高)

如果误删发生在支持快照的文件系统上,且近期有 snapshot,恢复成功率是 100%。这一节讲三类系统的快照操作。

12.1 LVM 快照

# 1. 创建快照
lvcreate -s -L 20G -n data_snap_recovery /dev/vg0/data

# 2. 挂载(ext4 快照直接挂载即可;xfs 在多 LV 同 VG 场景下可能要加 nouuid)
mount /dev/vg0/data_snap_recovery /mnt/snap
# 如果快照里是 xfs 且 VG 内出现 UUID 冲突,可加 -o nouuid:
# mount -o ro,nouuid /dev/vg0/data_snap_recovery /mnt/snap

# 3. 复制数据
cp -a /mnt/snap/data/backup/mysql/dump_20260608.sql /mnt/recovery/

# 4. 验证
diff /mnt/recovery/dump_20260608.sql /data/backup/mysql/dump_20260608.sql

# 5. 卸载 + 删除快照
umount /mnt/snap
lvremove -f /dev/vg0/data_snap_recovery

LVM 快照的局限:

  • 快照空间耗尽后会失效
  • 频繁写操作的 LV 不建议做大量快照
  • 快照本身影响写性能

12.2 btrfs 快照

# 1. 列出已有快照
btrfs subvolume list /data

# 2. 创建新快照
btrfs subvolume snapshot /data /data/.snapshots/$(date +%F_%H%M%S)

# 3. 恢复:把快照里的文件直接 cp 出来
# &nbsp; &nbsp;btrfs 快照是“可写快照”,可以挂载后操作
mkdir -p /mnt/snap
mount -o subvol=.snapshots/2026-06-09_021800 /dev/sdb1 /mnt/snap
ls /mnt/snap/data/backup/mysql/

# 4. 也可以用 btrfs restore 把整个 subvolume 恢复到另一个位置
btrfs restore /dev/sdb1 /mnt/recovery_btrfs

btrfs 的优势:

  • 快照成本极低(COW)
  • 快照嵌套快照
  • 可以做增量备份(btrfs send/receive

12.3 zfs 快照

# 1. 列出已有快照
zfs list -t snapshot | grep data

# 2. 创建新快照
zfs snapshot data@recover_$(date +%F_%H%M%S)

# 3. 访问快照
ls /data/.zfs/snapshot/recover_2026-06-09_021800/data/backup/mysql/

# 4. 复制数据
cp -a /data/.zfs/snapshot/recover_2026-06-09_021800/data/backup/mysql/* /mnt/recovery/

# 5. 删除快照
zfs destroy data@recover_2026-06-09_021800

zfs 的优势:

  • 快照是文件系统层的一等公民
  • zfs rollback 可以把整个 FS 回到某个时刻
  • 跨主机 zfs send/receive 是工业级备份

12.4 云盘快照

云上的块存储(EBS、CBS、Disk)都支持快照:

# AWS CLI
aws ec2 create-snapshot \
&nbsp; &nbsp; --volume-id vol-0abc1234 \
&nbsp; &nbsp; --description&nbsp;"pre-recovery-$(date +%F)"

# 阿里云 CLI
aliyun ecs CreateSnapshot \
&nbsp; &nbsp; --DiskId d-abc1234 \
&nbsp; &nbsp; --Description&nbsp;"pre-recovery-$(date +%F)"

# 腾讯云 CLI
tccli cbs CreateSnapshot \
&nbsp; &nbsp; --DiskId disk-abc1234

云盘快照的特点:

  • 底层是 COW,对原盘 IO 影响小
  • 快照创建通常秒级
  • 跨可用区复制功能可以做异地容灾
  • 收费按快照大小 + 保留时间

我们的生产环境在事件后第 3 周统一做了改造:所有 ext4 卷都迁到 LVM,每天一个 snapshot,保留 14 天。


13. 实战时间线:一次完整的误删恢复全过程

把前面讲的工具串起来,按真实事故的时间线给一个完整流程。假设场景:

  • 时间:2026-06-09 凌晨 02:17
  • 主机:backup-01.example.com,CentOS 7.9
  • 误删目录:/data/backup/mysql
  • 文件系统:ext4
  • 误删原因:脚本里 find ... -exec rm -rf {} \; 沿软链展开
  • 误删对象:约 200 个 mysqldump 文件,共 380GB
  • 备份:本地 LVM snapshot(昨天 02:00 整)

13.1 02:17 – 02:25:响应与止血

# 1. ssh 上去
ssh backup-01

# 2. 立刻停 cron
sudo systemctl stop crond
sudo systemctl mask crond

# 3. 停 mysqldump 任务(如果还在跑)
ps -ef | grep -E&nbsp;"mysqldump|cleanup"&nbsp;| grep -v grep
# 假设 PID 5678 是 cleanup.sh
sudo&nbsp;kill&nbsp;-STOP 5678 &nbsp;# 暂停进程,先不杀
# 也可以直接 kill,但要先把后面 lsof 信息抓了

# 4. 抓现场
sudo sh -c&nbsp;'date; uptime; df -h; df -i; free -h; mount > /tmp/mount.txt; lsof > /tmp/lsof.txt; lsblk > /tmp/lsblk.txt; blkid > /tmp/blkid.txt'&nbsp;> /tmp/initial_state.txt 2>&1

# 5. 立即把盘设为只读
sudo mount -o remount,ro /data
# 报 EBUSY,看下谁在写
sudo fuser -vm /data
# 假设是 mysqldump 进程
sudo&nbsp;kill&nbsp;-STOP $(pidof mysqldump)
sudo mount -o remount,ro /data
# 这次成功了

# 6. 验证
mount | grep /data

13.2 02:25 – 02:30:LVM 快照

# 1. 查看 VG 空间
sudo vgdisplay vg0 | grep -E&nbsp;"VG Name|Free"
# 假设 Free: 50G

# 2. 创建快照
sudo lvcreate -s -L 30G -n data_snap_recovery /dev/vg0/data

# 3. 挂载快照
sudo mkdir -p /mnt/snap
sudo mount -o ro /dev/vg0/data_snap_recovery /mnt/snap

# 4. 验证快照可读
sudo ls -la /mnt/snap/data/backup/mysql/ | head -20
# 看到 380GB 的文件都在

13.3 02:30 – 02:50:lsof 抢救

# 1. 抓 deleted
sudo lsof | grep deleted | grep backup > /tmp/deleted_files.txt
# 看到约 30 个文件被 mysqldump 进程持有

# 2. 准备恢复目录
sudo mkdir -p /mnt/recovery

# 3. 批量恢复
sudo /opt/scripts/recover_deleted.sh /mnt/recovery
# 恢复出 30 个文件,约 80GB

# 4. 验证
sudo ls -la /mnt/recovery/ | head -20

13.4 02:50 – 04:30:extundelete 全量恢复

# 1. 准备恢复目标盘
sudo mkdir -p /mnt/recovery2
sudo mount /dev/sdc1 /mnt/recovery2 &nbsp;# 假设 sdc1 是 1TB 独立盘

# 2. 卸载原盘(避免误操作)
sudo umount /mnt/snap
# 保留 snapshot lv 不动

# 3. 跑 extundelete
cd&nbsp;/mnt/recovery2
sudo extundelete /dev/sdb1 --restore-all --before&nbsp;"2026-06-09 02:00:00"
# 这一步大约 1 小时

# 4. 验证
ls -la /mnt/recovery2/RECOVERED_FILES/ | head
ls -la /mnt/recovery2/RECOVERED_FILES/data/backup/mysql/ | head

13.5 04:30 – 06:00:业务校验

# 1. 把恢复出来的 mysqldump 文件加载到测试库
for&nbsp;f&nbsp;in&nbsp;/mnt/recovery2/RECOVERED_FILES/data/backup/mysql/dump_*.sql;&nbsp;do
&nbsp; &nbsp;&nbsp;# 抽样前 100 行
&nbsp; &nbsp; head -100&nbsp;"$f"&nbsp;| mysql -u root -p <db_test>
&nbsp; &nbsp;&nbsp;if&nbsp;[ $? -ne 0 ];&nbsp;then
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo"BROKEN:&nbsp;$f"
&nbsp; &nbsp;&nbsp;fi
done

# 2. 校验关键文件大小
find /mnt/recovery2/RECOVERED_FILES/data/backup/mysql/ -type&nbsp;f -size -100k -ls
# 找出 0 字节和异常小的文件

# 3. 对比 mysqldump 的预期行数
mysql -u root -p -e&nbsp;"SELECT * FROM <db>.tables"&nbsp;| wc -l
# 跟某个 dump 文件的 INSERT 行数对比

13.6 06:00 – 08:00:补传 + 业务验证

# 1. 把恢复出来的文件推回业务机
rsync -avz /mnt/recovery2/RECOVERED_FILES/data/backup/mysql/ \
&nbsp; &nbsp; backup-target:/data/backup/mysql/

# 2. 让应用方做端到端校验
# &nbsp; &nbsp;业务方反馈:恢复出来的文件能正常恢复
# &nbsp; &nbsp;缺失的 12 个文件从异地机房拉

# 3. 通知变更完成

13.7 复盘

  • 完整复盘会安排在第二天上午
  • 主因:旧脚本没做 Code Review
  • 根因:缺监控 + 缺审计 + 缺流程
  • 改进:所有清理脚本必须 Code Review、必须 dry-run

14. 风险点与不可恢复场景

下面这些场景,恢复工具都救不回来。提前认清边界。

14.1 块已被覆写

# 查看空闲块水位
dumpe2fs /dev/sdb1 | grep -E&nbsp;"Free blocks|Free inodes"

Free blocks 越小,说明可用空间越紧张,覆写风险越高。如果空闲块数已经很少,新数据写入会很快把误删文件覆盖。

14.2 文件系统已重格式化

# 如果有人在修复过程中 mkfs 了
mkfs.ext4 /dev/sdb1
# 那么元数据被重置,恢复工具扫到的是全新的 FS 结构

遇到这种情况,extundelete 几乎无解,唯一的希望是 photorec 按块扫。

14.3 磁盘出现坏道

# smartctl 报告坏道
smartctl -a /dev/sdb | grep -E&nbsp;"Reallocated|Pending|Uncorrectable"

坏道上的数据物理上读不出来,恢复出来的文件会有零字节块或随机内容。

14.4 文件被部分覆写

# 假设 dump_20260608.sql 被覆写了头部 1MB
# 恢复出来的文件从原 1MB 位置开始,前面 1MB 是新数据

这种文件通常校验失败,需要从其他渠道(远端备份、其它机器)补全。

14.5 文件名彻底丢失

extundelete 恢复出来的文件名是 inode_12345.dump 这种,需要靠 inode 推回去。如果连 inode 都没记(应用层没打 tag),就只能按文件大小、修改时间、文件类型人工归类。

14.6 加密文件系统

LUKS 加密的 FS,恢复时需要解锁。如果密钥丢了,数据不可救。生产环境建议:

  • 密钥用 key escrow(Key Custodian)机制
  • 不要只放在一个人的密码本里
  • LUKS 头要做异地备份

14.7 写入放大

如果误删的是数据库文件,且 DB 仍在跑,DB 的 checkpoint、redolog 写入会持续覆写空闲块。这种情况下,越早停 DB 越好。


15. 防误删:制度、命令、备份、监控

讲完恢复,必须讲防御。下面是我们在事件后落地的一套防御体系。

15.1 制度层

15.1.1 清理脚本 Code Review 制度

任何 find ... -exec rmrm -rfshred 等破坏性命令,必须:

  • 在 git 仓库里
  • 经过至少 1 人 review
  • 必须有 dry-run 选项
  • 必须有过期时间判断(不能只判断目录名)

15.1.2 清理脚本必须有 dry-run

#!/bin/bash
# cleanup.sh
# 清理 30 天前的旧备份

# 必须支持 DRY_RUN 环境变量
DRY_RUN=${DRY_RUN:-1}# 默认 dry-run
LOG_FILE=${LOG_FILE:-/var/log/cleanup.log}

log() {
&nbsp; &nbsp;&nbsp;echo"$(date '+%F %T')&nbsp;$*"&nbsp;| tee -a&nbsp;"$LOG_FILE"
}

if&nbsp;[&nbsp;"$DRY_RUN"&nbsp;=&nbsp;"1"&nbsp;];&nbsp;then
&nbsp; &nbsp;&nbsp;log"DRY-RUN: would remove the following:"
&nbsp; &nbsp; find /data/backup/mysql -type&nbsp;f -mtime +30 -print
&nbsp; &nbsp;&nbsp;exit&nbsp;0
fi

# 真正的清理逻辑
log"REAL-CLEAN: starting"
find /data/backup/mysql -type&nbsp;f -mtime +30 -print&nbsp;-delete
log"REAL-CLEAN: done"

使用方式:

# 1. 演练
DRY_RUN=1 LOG_FILE=/var/log/cleanup_test.log /opt/scripts/cleanup.sh

# 2. 确认无误后真实运行
DRY_RUN=0 LOG_FILE=/var/log/cleanup_real.log /opt/scripts/cleanup.sh

15.1.3 强制二次确认

#!/bin/bash
# rm_with_confirm.sh
# 包装 rm,强制二次确认

TARGET="$1"

if&nbsp;[ -z&nbsp;"$TARGET"&nbsp;];&nbsp;then
&nbsp; &nbsp;&nbsp;echo"Usage:&nbsp;$0&nbsp;<path>"
&nbsp; &nbsp;&nbsp;exit&nbsp;1
fi

# 1. 提示
echo"==== WARNING ===="
echo"About to remove:&nbsp;$TARGET"
echo"Resolved path:&nbsp;$(readlink -f "$TARGET")"
echo"Disk usage:&nbsp;$(du -sh "$TARGET" 2>/dev/null | awk '{print $1}')"
echo"==== END ===="

# 2. 强制输入 YES
read&nbsp;-p&nbsp;"Type 'YES' to continue: "&nbsp;confirm
if&nbsp;[&nbsp;"$confirm"&nbsp;!=&nbsp;"YES"&nbsp;];&nbsp;then
&nbsp; &nbsp;&nbsp;echo"Aborted."
&nbsp; &nbsp;&nbsp;exit&nbsp;1
fi

# 3. 删除
rm -rf --&nbsp;"$TARGET"
echo"Removed."

15.1.4 审计日志

# 在 /etc/profile 里加 alias
alias&nbsp;rm='/usr/local/bin/audit_rm.sh'
# /usr/local/bin/audit_rm.sh
#!/bin/bash
LOG_FILE=/var/log/rm_audit.log
USER=$(whoami)
PWD_PATH=$(pwd)
TIMESTAMP=$(date&nbsp;'+%F %T')

# 记录命令
echo&nbsp;"$TIMESTAMP&nbsp;user=$USER&nbsp;pwd=$PWD_PATH&nbsp;cmd=rm args=$*"&nbsp;>>&nbsp;"$LOG_FILE"

# 调用真实 rm
exec&nbsp;/bin/rm&nbsp;"$@"

15.2 命令层

15.2.1 替换 rm

trash-cli 是一个跨平台的回收站替代品:

# Fedora / RHEL 8 + EPEL
yum install -y trash-cli

# Ubuntu / Debian
apt-get install -y trash-cli

# 仓库里没有时,pip 兜底
pip3 install trash-cli

# 使用
trash-put foo.txt &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 移动到回收站
trash-list &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 列出回收站
trash-restore foo.txt &nbsp; &nbsp; &nbsp;&nbsp;# 恢复
trash-empty &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 清空回收站

# 替换 alias
alias&nbsp;rm='trash-put'

trash-cli 的坑:

  • 跨主机不通用
  • 跨用户不通用
  • 习惯 rm 的同学要过渡期

15.2.2 safe-rm

# 安装
yum install -y safe-rm

# 配置黑名单
cat /etc/safe-rm.conf
/
/etc
/usr
/var
/data/backup &nbsp;# 把重要目录加进去

safe-rm 是一个 rm 的 wrapper,会拦截对黑名单路径的删除。

15.2.3 慎用 find -exec rm

find ... -exec rm -rf {} \; 配合软链非常危险。find 默认不跟软链,但 -L 会跟。

# 安全做法:先 print 看一下
find /data/backup/mysql -type&nbsp;f -mtime +30 -print

# 确认无误后 -delete
find /data/backup/mysql -type&nbsp;f -mtime +30 -delete

find -delete 跟 find -exec rm 的区别:

  • -delete 是 find 内置的,更安全(不会执行任意命令)
  • -exec rm 是执行外部命令,软链攻击面更大

15.2.4 通配符小心

# 危险写法
rm -rf /data/backup/*

# 如果 /data/backup 是空目录,而当前 shell 把 * 展开成别的,就出事了
# 安全写法
rm -rf /data/backup/*.sql &nbsp;# 明确匹配

# 更安全:先 ls
ls /data/backup/*.sql
rm -rf /data/backup/*.sql

15.3 备份层

15.3.1 3-2-1 备份策略

  • 3 份副本
  • 2 种介质
  • 1 份异地

对于我们这种备份服务器,3 份副本的实现:

  1. 本地 LVM snapshot
  2. 异地 rsync
  3. 对象存储(S3/OSS/COS)

15.3.2 自动 snapshot 脚本

#!/bin/bash
# daily_snapshot.sh
# 每天凌晨 2 点创建 LVM snapshot,保留 7 天

VG_NAME=vg0
LV_NAME=data
SNAP_SIZE=20G
KEEP_DAYS=7
SNAP_PREFIX=data_daily

# 1. 创建快照
DATE=$(date +%Y%m%d)
SNAP_NAME="${SNAP_PREFIX}_${DATE}"
lvcreate -s -L&nbsp;${SNAP_SIZE}&nbsp;-n&nbsp;${SNAP_NAME}&nbsp;/dev/${VG_NAME}/${LV_NAME}&nbsp;2>&1 | logger -t snapshot

if&nbsp;[ $? -ne 0 ];&nbsp;then
&nbsp; &nbsp; logger -t snapshot&nbsp;"ERROR: failed to create snapshot&nbsp;${SNAP_NAME}"
&nbsp; &nbsp;&nbsp;exit&nbsp;1
fi

# 2. 删除过期快照
for&nbsp;old_snap&nbsp;in&nbsp;$(lvs --noheadings -o lv_name&nbsp;${VG_NAME}&nbsp;| grep&nbsp;"${SNAP_PREFIX}_");&nbsp;do
&nbsp; &nbsp; snap_date=$(echo$old_snap&nbsp;| sed&nbsp;"s/${SNAP_PREFIX}_//")
&nbsp; &nbsp;&nbsp;if&nbsp;[ -n&nbsp;"$snap_date"&nbsp;];&nbsp;then
&nbsp; &nbsp; &nbsp; &nbsp; snap_ts=$(date -d&nbsp;"$snap_date"&nbsp;+%s 2>/dev/null)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;[ $? -eq 0 ];&nbsp;then
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; age_days=$(( ($(date +%s) - snap_ts) / 86400 ))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;[&nbsp;$age_days&nbsp;-gt&nbsp;$KEEP_DAYS&nbsp;];&nbsp;then
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lvremove -f /dev/${VG_NAME}/${old_snap}&nbsp;2>&1 | logger -t snapshot
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fi
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fi
&nbsp; &nbsp;&nbsp;fi
done

15.3.3 异地备份

# rsync over ssh
rsync -avz --delete \
&nbsp; &nbsp; /data/backup/mysql/ \
&nbsp; &nbsp; [email protected]:/data/backup/mysql/

# 用对象存储
aws s3 sync /data/backup/mysql/ s3://my-bucket/mysql/ --delete

15.4 监控层

15.4.1 监控重要目录的存在性

#!/bin/bash
# /opt/mon/check_backup.sh
# 检查关键目录是否存在

CRITICAL_DIRS=(
&nbsp; &nbsp;&nbsp;"/data/backup/mysql"
&nbsp; &nbsp;&nbsp;"/data/backup/app"
&nbsp; &nbsp;&nbsp;"/data/backup/logs"
)

for&nbsp;dir&nbsp;in"${CRITICAL_DIRS[@]}";&nbsp;do
&nbsp; &nbsp;&nbsp;if&nbsp;[ ! -d&nbsp;"$dir"&nbsp;];&nbsp;then
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 触发告警
&nbsp; &nbsp; &nbsp; &nbsp; curl -X POST&nbsp;"https://alert.example.com/alert"&nbsp;\
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -d&nbsp;"host=$(hostname)&dir=$dir&msg=directory missing"
&nbsp; &nbsp;&nbsp;fi
done

15.4.2 监控文件数量

# 写一个 prometheus textfile collector
CRITICAL_DIRS=(
&nbsp; &nbsp;&nbsp;"/data/backup/mysql"
)

for&nbsp;dir&nbsp;in&nbsp;"${CRITICAL_DIRS[@]}";&nbsp;do
&nbsp; &nbsp; count=$(find&nbsp;"$dir"&nbsp;-type&nbsp;f 2>/dev/null | wc -l)
&nbsp; &nbsp;&nbsp;echo&nbsp;"backup_file_count{dir=\"$dir\"}&nbsp;$count"&nbsp;>> /var/lib/node_exporter/textfile/backup.prom
done

15.4.3 监控清理脚本的运行

# 在 cleanup.sh 里发送心跳
logger -t cleanup&nbsp;"started with DRY_RUN=$DRY_RUN"
# 同时把日志发到集中日志系统(ELK / Loki)
curl -X POST&nbsp;"https://logs.example.com/collect"&nbsp;\
&nbsp; &nbsp; -d&nbsp;"{\"job\":\"cleanup\",\"status\":\"started\",\"host\":\"$(hostname)\"}"

15.4.4 告警:删除事件

#!/bin/bash
# /opt/mon/audit_rm_watch.sh
# 实时监控 /var/log/rm_audit.log,发现危险操作立即告警

tail -F /var/log/rm_audit.log |&nbsp;while&nbsp;read&nbsp;-r line;&nbsp;do
&nbsp; &nbsp;&nbsp;# 检测 -rf、/、* 这类危险模式
&nbsp; &nbsp;&nbsp;if&nbsp;echo&nbsp;"$line"&nbsp;| grep -qE&nbsp;"(rm -rf|/ | rm -rf)";&nbsp;then
&nbsp; &nbsp; &nbsp; &nbsp; curl -X POST&nbsp;"https://alert.example.com/alert"&nbsp;\
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -d&nbsp;"host=$(hostname)&line=$line&severity=high"
&nbsp; &nbsp;&nbsp;fi
done

15.5 配置层

15.5.1 /etc/skel/.bashrc 加 alias

# /etc/skel/.bashrc
alias&nbsp;rm='echo "Use trash-put or /opt/scripts/safe_rm.sh"; false'
alias&nbsp;mv='mv -i'
alias&nbsp;cp='cp -i'

新建用户会自动继承。生产环境谨慎给 root 用。

15.5.2 /etc/profile.d/rm_alias.sh

# 强制所有用户加载
cat > /etc/profile.d/rm_alias.sh <<&nbsp;'EOF'
alias&nbsp;rm='/usr/local/bin/audit_rm.sh'
alias&nbsp;cp='cp -i'
alias&nbsp;mv='mv -i'
EOF
chmod +x /etc/profile.d/rm_alias.sh

16. 替代 rm 的安全删除方案

如果你的团队能接受“换个命令”,下面是几个更安全的替代品。

16.1 trash-cli

前面讲过,跨平台,使用简单。缺点是不解决软链问题。

16.2 rmtrash

# macOS 用户熟悉的
brew install rmtrash

16.3 移动到隔离目录

#!/bin/bash
# /opt/bin/saferm
# 移动到隔离目录,30 天后自动清理

QUARANTINE=/var/spool/quarantine
RETENTION_DAYS=30

mkdir -p&nbsp;"$QUARANTINE"

for&nbsp;target&nbsp;in"$@";&nbsp;do
&nbsp; &nbsp; real=$(readlink -f&nbsp;"$target")
&nbsp; &nbsp; ts=$(date +%Y%m%d_%H%M%S)
&nbsp; &nbsp; safe=$(echo"$real"&nbsp;| tr&nbsp;'/''_')
&nbsp; &nbsp; mv&nbsp;"$target""$QUARANTINE/${ts}_${safe}"
done

# 清理过期
find&nbsp;"$QUARANTINE"&nbsp;-mtime +$RETENTION_DAYS&nbsp;-delete

16.4 用 Git / Mercurial 做版本控制

对于配置文件、关键脚本:

# 初始化
cd&nbsp;/opt/scripts
git init
git add .
git commit -m&nbsp;"initial"

# 每次改之前
git commit -am&nbsp;"before change rm logic"

# 改错了
git checkout HEAD -- cleanup.sh

16.5 用 Git LFS / DVC 做大数据版本控制

对于数据文件,可以用 DVC(Data Version Control)做轻量级版本管理。


17. 复盘总结与给初中级运维的建议

事故复盘是一线运维的“软基建”,但很多团队不做或者走形式。我们这次复盘真正落地的有几条:

17.1 复盘要点

  1. 主因:清理脚本没有 Code Review,没有 dry-run,配合软链造成扩删
  2. 根因:
  • 缺流程:清理脚本被当作“杂事”
  • 缺监控:误删到告警之间隔了 17 分钟
  • 缺审计:rm 操作没有二次确认
  • 缺演练:脚本变更没在预发演练
  1. 影响:约 380GB 数据不可见,异地备份还有,但延迟 1 天恢复

17.2 行动项

  • 所有清理脚本纳入 Git 管理 + Code Review
  • 部署 audit_rm 全局包装
  • 关键目录加文件数量监控 + 异常告警
  • 备份服务器从 ext4 迁到 ext4 + LVM,启用 daily snapshot
  • 异地备份加密传输 + 完整性校验

17.3 给初中级运维的几条建议

  1. 任何 rm -rf 之前先 ls 一遍,哪怕你自己写的脚本
  2. find -delete 优于 find -exec rm,是更安全的写法
  3. 生产环境的清理脚本必须支持 dry-run,上线前演练
  4. 软链是 rm -rf 的最大帮凶,清理脚本要显式 -type d 或 -type l 区分
  5. 重要目录加监控,目录存在性 + 文件数量 + 文件总大小
  6. 定期做恢复演练,每年至少一次真实数据恢复测试
  7. 永远不要在生产环境做新工具的“第一次使用”,先在测试机
  8. 培养“误删后第一反应是拍照不是动手”的习惯

17.4 给团队 Leader 的建议

  1. 清理任务走变更流程,跟代码发布一样严格
  2. 强制 Code Review,把 Git 仓库的权限收紧
  3. 建立“防误删日”演练,每季度一次
  4. 配置 review 检查清单,把软链、绝对路径、rm 包装列入
  5. 监控告警必须有“删除事件”分类

18. 附录 A:常用命令速查表

18.1 状态检查

| 命令 | 用途 | | — | — | | df -h | 查看磁盘空间 | | df -i | 查看 inode 使用 | | mount | 查看挂载点 | | cat /proc/mounts | 内核视角的挂载信息 | | blkid | 查看块设备文件系统类型 | | lsblk | 树形查看块设备 | | iostat -dx 1 5 | 磁盘 IO 监控 | | dmesg | tail | | smartctl -H /dev/sdX | 磁盘健康度 |

18.2 恢复工具

| 工具 | 适用 FS | 关键参数 | | — | — | — | | extundelete | ext2/3/4 | --restore-all --before "时间" | | debugfs | ext2/3/4 | lsdeldump <inode> | | xfs_undelete | xfs | -t <dir> | | xfs_db | xfs | 诊断 | | testdisk | 多 FS | 交互式 | | photorec | 多 FS | 按块扫 | | btrfs restore | btrfs | 整 FS 恢复 | | lsof | grep deleted | 任何 FS | | zfs rollback | zfs | 回滚到 snapshot |

18.3 LVM 操作

| 命令 | 用途 | | — | — | | vgdisplay | 查看 VG | | lvdisplay | 查看 LV | | lvcreate -s -L 20G -n snap | 创建快照 | | lvremove | 删除快照 | | mount -o ro /dev/vg/lv | 挂载快照 |

18.4 btrfs 操作

| 命令 | 用途 | | — | — | | btrfs subvolume list | 列出 subvolume | | btrfs subvolume snapshot | 创建快照 | | btrfs restore | 恢复整个 FS | | btrfs send/receive | 增量备份 |

18.5 zfs 操作

| 命令 | 用途 | | — | — | | zfs list -t snapshot | 列出快照 | | zfs snapshot | 创建快照 | | zfs rollback | 回滚 | | zfs send/receive | 增量备份 |


19. 附录 B:常见错误码与排查

| 错误码 | 含义 | 应对 | | — | — | — | | EBUSY mount | FS 有进程在写 | fuser 找进程,停止或卸载 | | EACCES debugfs | 权限不足 | 用 root | | ENOSPC extundelete | 输出盘空间不足 | 换大点的目标盘 | | EIO dd | 磁盘读错误 | 加 conv=noerror,sync | | EINVAL mkfs | 文件系统不识别 | 检查 blkid | | ENOMEM debugfs | 内存不足 | 加大内存或加 swap |


20. 附录 C:常见误区澄清

20.1 误区 1:rm 之后立刻 sync 还能救

错。sync 只把内存里的脏页刷到磁盘。rm 已经把目录项和 inode 元数据改了,sync 不能“撤销”这个改动。

20.2 误区 2:磁盘格式化后立刻重启就找不到原数据

不一定。元数据被重置,但 block 数据还在。photorec 还能扫到一部分。但成功率和 FS 类型、覆写率强相关。

20.3 误区 3:rm -rf / 一定能把系统搞坏

取决于根分区的类型。如果根分区是单独 mount 的,rm -rf / 不会真的删根目录(Linux 内核会拒绝)。但如果根目录是用 bind mount 把 /data 映射到 / 的,就会真的全删。

20.4 误区 4:xfs 不能恢复

不严谨。xfs_undelete 多数情况下能恢复部分文件,photorec 也能扫一部分。成功率比 ext4 低,但并不是 0。

20.5 误区 5:固态硬盘恢复成功率低

不严谨。SSD 的 TRIM 指令会主动清零空闲块。如果 SSD 开启了 TRIM 且运行了足够时间,恢复率确实接近 0。但很多企业级 SSD 默认关闭 TRIM,或延迟 TRIM,恢复率跟 HDD 接近。hdparm -I /dev/sdX | grep TRIM 可以看是否支持。

20.6 误区 6:恢复后文件能 100% 还原

不严谨。恢复工具只保证 block 层面拼回去,元数据(创建时间、权限、扩展属性、ACL)可能丢失。

20.7 误区 7:dd 镜像比 rsync 安全

各有各的用法。dd 适合整盘镜像、无法 mount 的磁盘、底层读取场景。rsync 适合文件系统级别的复制。

20.8 误区 8:rm -rf 跟 rm 等价

错。-r 是 recursive,-f 是 force(不提示、忽略不存在的文件)。rm -rf 在交互场景下完全不会等你。


21. 附录 D:极端场景下的兜底方案

下面几个方案是“实在救不回来”才考虑。

21.1 联系数据恢复公司

国内主流公司:

  • 苏州某知名厂商(涉密)
  • 各类“专业数据恢复”服务

服务特点:

  • 价格贵(万到几十万)
  • 周期长(几天到几周)
  • 需要把磁盘邮寄过去
  • 有保密协议

适用于:

  • 关键业务数据
  • 涉及合规审计
  • 内部团队已无能力

21.2 从备份恢复

如果误删的文件是“备份数据”本身,恢复路径就是从“备份的备份”恢复:

  • 异地 rsync 同步
  • 对象存储快照
  • 磁带归档(LTO)

磁带是“最后的最后”的手段:

  • 成本低
  • 容量大
  • 恢复需要特定设备
  • 多数公司已经不再用

21.3 业务层降级

实在救不回来,业务层要启动降级:

  • 部分功能关闭
  • 数据不完整的状态先跑
  • 业务方接受降级方案
  • 后续逐步补全

22. 附录 E:磁盘镜像与远程恢复

当恢复工具无法直接操作原盘时,需要做磁盘镜像。

22.1 dd 镜像

# 本地镜像
dd&nbsp;if=/dev/sdb of=/mnt/recovery/sdb.img bs=4M status=progress conv=noerror,sync

# 远程镜像
dd&nbsp;if=/dev/sdb bs=4M conv=noerror,sync | gzip | ssh user@backup&nbsp;"cat > /mnt/recovery/sdb.img.gz"

# 还原
dd&nbsp;if=/mnt/recovery/sdb.img of=/dev/sdb bs=4M status=progress

22.2 ddrescue 增量恢复

# 安装
yum install -y ddrescue

# 第一次:全量
ddrescue /dev/sdb /mnt/recovery/sdb.img /mnt/recovery/sdb.rescue.log

# 第二次:跳过已读
ddrescue -d -r3 /dev/sdb /mnt/recovery/sdb.img /mnt/recovery/sdb.rescue.log

ddrescue 比 dd 智能,能跳过坏道并多次尝试。

22.3 镜像后操作

# 把镜像文件当磁盘用
losetup -f /mnt/recovery/sdb.img
losetup -a

# 在 loop 设备上跑 extundelete
extundelete /dev/loop0 --restore-all

23. 附录 F:演练剧本(生产环境慎用)

23.1 演练环境准备

# 准备一台测试机
# 创建一个小 FS
dd&nbsp;if=/dev/zero of=/tmp/test.img bs=1M count=1024
mkfs.ext4 /tmp/test.img
mkdir -p /mnt/test
mount -o loop /tmp/test.img /mnt/test

# 准备测试数据
mkdir -p /mnt/test/{mysql,app,logs}
echo"test data"&nbsp;> /mnt/test/mysql/dump.sql
dd&nbsp;if=/dev/urandom of=/mnt/test/mysql/large_file bs=1M count=10

# 记录元数据
ls -la /mnt/test/mysql > /tmp/before_state.txt
ls -i /mnt/test/mysql > /tmp/before_inodes.txt

23.2 模拟误删

# 模拟误删
rm -rf /mnt/test/mysql

23.3 恢复演练

# 1. 立即 remount ro
mount -o remount,ro /mnt/test

# 2. extundelete
mkdir -p /mnt/recovery
cd&nbsp;/mnt/recovery
extundelete /tmp/test.img --restore-all

# 3. 验证
diff -r /mnt/recovery/RECOVERED_FILES/mysql /tmp/before_state.txt

23.4 演练评估

  • 成功标准:恢复出来的文件能正常打开
  • 失败标准:文件 0 字节、内容损坏
  • 演练报告:记录耗时、命令、结果,写入 SOP

24. 附录 G:监控指标建议

对于备份目录的健康度,建议监控以下指标:

# 1. 关键目录文件数量
backup_file_count{dir="/data/backup/mysql"}

# 2. 关键目录总大小
backup_dir_size_bytes{dir="/data/backup/mysql"}

# 3. 关键目录最近一次修改时间
backup_last_modified_timestamp{dir="/data/backup/mysql"}

# 4. 磁盘使用率
node_filesystem_avail_bytes{mountpoint="/data"}

# 5. inode 使用率
node_filesystem_files_free{mountpoint="/data"}

# 6. LVM 快照数量
lvm_snapshot_count{vg="vg0"}

# 7. 异地备份最后一次同步时间
remote_backup_last_sync_timestamp

告警规则示例:

groups:
&nbsp;&nbsp;-name:backup_alerts
&nbsp; &nbsp;&nbsp;rules:
&nbsp; &nbsp; &nbsp;&nbsp;-alert:BackupDirectoryMissing
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;expr:backup_file_count{dir="/data/backup/mysql"}==0
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for:5m
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;labels:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;severity:critical
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;annotations:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;summary:"备份目录文件数为 0"

&nbsp; &nbsp; &nbsp;&nbsp;-alert:BackupDirectoryLowFileCount
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;expr:backup_file_count{dir="/data/backup/mysql"}<100
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for:30m
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;labels:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;severity:warning
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;annotations:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;summary:"备份目录文件数低于阈值"

&nbsp; &nbsp; &nbsp;&nbsp;-alert:BackupSyncFailed
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;expr:time()-remote_backup_last_sync_timestamp>86400
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for:1h
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;labels:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;severity:critical
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;annotations:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;summary:"异地备份超过 24 小时未同步"

25. 附录 H:工具对照表

| 工具 | 适用场景 | 难度 | 成功率 | 备注 | | — | — | — | — | — | | extundelete | ext4 整目录恢复 | 低 | 高 | 首选 | | debugfs | 按 inode 精细恢复 | 中 | 高 | 配合元数据 | | xfs_undelete | xfs 目录恢复 | 低 | 中 | 工具较新 | | testdisk | 全 FS 扫描 | 中 | 中 | 交互式 | | photorec | 按块特征扫描 | 中 | 中低 | 文件名丢失 | | lsof | 进程持有文件 | 低 | 高 | 必查 | | LVM snapshot | 整盘回滚 | 低 | 100% | 依赖 snapshot | | btrfs restore | btrfs 整盘恢复 | 中 | 高 | | | zfs rollback | zfs 整盘回滚 | 低 | 100% | 依赖 snapshot |


26. 附录 I:SOP 模板

# 数据误删应急响应 SOP

## 触发条件
-&nbsp;收到删除事件告警
-&nbsp;用户报告文件丢失
-&nbsp;监控显示目录文件数突降

## 响应步骤
1.&nbsp;确认事故(10 分钟内)
&nbsp; &nbsp;-&nbsp;联系报告人确认现象
&nbsp; &nbsp;-&nbsp;ssh 到目标主机初步确认
2.&nbsp;立即止血(5 分钟内)
&nbsp; &nbsp;-&nbsp;停 cron、停相关进程
&nbsp; &nbsp;-&nbsp;remount ro 或做 LVM 快照
3.&nbsp;现场记录(15 分钟内)
&nbsp; &nbsp;-&nbsp;抓 mount、lsof、ps、dmesg
4.&nbsp;评估恢复方案(30 分钟内)
&nbsp; &nbsp;-&nbsp;确认 FS 类型
&nbsp; &nbsp;-&nbsp;选择恢复工具
5.&nbsp;执行恢复(视情况)
&nbsp; &nbsp;-&nbsp;extundelete / debugfs / lsof
&nbsp; &nbsp;-&nbsp;写入独立磁盘
6.&nbsp;业务校验
&nbsp; &nbsp;-&nbsp;文件大小、类型、内容
&nbsp; &nbsp;-&nbsp;应用方确认
7.&nbsp;复盘(事故后 24 小时内)
&nbsp; &nbsp;-&nbsp;写复盘文档
&nbsp; &nbsp;-&nbsp;落地行动项

27. 附录 J:推荐阅读与工具

  • ext2fsprogs 文档:debugfs、e2fsck、mke2fs 的官方手册
  • e2fsprogs 源码:理解 ext4 内部实现
  • LVM 官方文档:理解 snapshot 实现
  • BTRFS Wiki:理解 CoW 文件系统
  • ZFS 文档:理解 zfs send/receive

工具:

  • extundelete (sf.net)
  • testdisk / photorec (cgsecurity.org)
  • sleuthkit (sleuthkit.org)
  • ddrescue (gnu.org)
  • trash-cli (github.com/andreafrancia/trash-cli)

28. 结语

rm -rf 不可怕,可怕的是“以为自己有备份所以不担心”。做运维越久,越会敬畏“删除”这个动作:它不像写,写错了能 git revert;它更像 SQL 的 DROP TABLE,跑完就没了。

本文的真正意义不是教你用 extundelete 救命,而是希望你:

  1. 理解文件系统原理,对“删除”有敬畏
  2. 在动手前先想清楚影响面
  3. 永远有 Plan B(备份、快照、Code Review)
  4. 把防误删做成制度、做成工具、做成肌肉记忆

技术会变,ext4 会变成 btrfs,centos 会变成 rocky,rm 会被各种 wrapper 包装。但“删除”这件事的本质不会变:它永远是不可逆的、永远需要审批的、永远需要备份的。

希望这篇文章能让你下次面对 rm -rf 时,多一份从容,多一份底气。


29. 引用与版本说明

  • 本文涉及的内核版本以 3.10、4.18、5.4 为例
  • ext4 格式参考 kernel.org Documentation/filesystems/ext4
  • LVM 来自 Red Hat 官方手册
  • btrfs 来自 btrfs.wiki.kernel.org
  • zfs 来自 OpenZFS 文档

不同版本字段可能略有差异,实际操作请以目标环境的工具版本手册为准。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:马哥Linux运维 点击关注 👉 点击关注 👉《Linux 下 rm -rf 误删文件后,我们是如何完成数据恢复的》

靶机渗透-DC9 网络安全文章

靶机渗透-DC9

文章总结: 本文详细记录了DC-9靶机渗透测试全过程,通过信息收集发现SQL注入点并利用sqlmap获取管理员凭据,登录后台后利用文件包含漏洞读取knockd配
评论:0   参与:  0