Linux 计划任务安全核查:异常 crontab 识别、chattr 锁定与回滚清单

枫少@KillBoy
枫少@KillBoy
枫少@KillBoy
管理员
383
文章
0
粉丝
安全运维1 28字数 2894阅读9分38秒阅读模式
AI智能摘要
计划任务排查最怕漏看,更怕看完就删:异常条目可能藏在系统 crontab、cron.d、run-parts 目录、用户 crontab 甚至 systemd timer 中,误删业务任务往往比入侵更快引发故障。文章给出只读盘点、基线快照与可疑特征判读,并强调 chattr +i 只能小步止血、无法清除恶意条目。锁定前该先确认什么,才能防回归又不挡住正常变更?
— AI 生成的文章内容摘要

计划任务排查最怕两件事:一是漏看,二是看完就动手。开始前,先界定影响范围和需要观察的业务路径:站点首页与后台是否可访问、登录与上传是否正常、PHP-FPM 与数据库连接是否正常、备份任务是否照旧产出文件、证书续期与日志轮转是否按点执行、缓存清理和临时文件回收是否仍在跑。这些路径里,任何一条依赖 cron,本篇文章的改动都可能影响它。下面的操作都假定你在已获授权的服务器上执行,范围只到“盘点、判断、小步锁定、验证回滚”。

运维人员在机房终端前核对计划任务清单

一、先盘点:计划任务的来源不止一个 crontab -l

很多人只执行 crontab -l 就以为查完了,这只覆盖当前用户。linux 上至少还有五类来源,必须逐类过一遍。

来源路径格式要点常见遗漏
系统 crontab/etc/crontab比用户 crontab 多一个“执行用户”字段只当配置文件看,没逐行核对用户列
cron.d 片段/etc/cron.d/*同样是六段式(含用户字段)软件包安装时新增的片段没人复核
run-parts 目录/etc/cron.hourly、daily、weekly、monthly放可执行脚本,文件名通常不能带点脚本内容被替换,目录列表却没变
用户 crontab/var/spool/cron/(RHEL 系)或 /var/spool/cron/crontabs/(Debian/Ubuntu)五段式,无用户字段只有 root 能 crontab -l -u 逐个看
其他调度器/etc/anacrontab、systemd timer、at 队列各自独立语法攻击者改用 timer 或 anacron 落持久化

一次跑完的盘点命令(在 root 下执行,全部为只读操作):

# 系统级
ls -la /etc/crontab /etc/cron.d/ 2>/dev/null
ls -la /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly 2>/dev/null
cat /etc/anacrontab 2>/dev/null
systemctl list-timers --all --no-pager

# 用户级:逐个账号导出
for u in $(cut -d: -f1 /etc/passwd); do
  out=$(crontab -l -u "$u" 2>/dev/null)
  [ -n "$out" ] && printf '===== %s =====n%sn' "$u" "$out"
done

# 直接看落盘文件,留意 mtime 与属主
ls -la /var/spool/cron/ /var/spool/cron/crontabs/ 2>/dev/null

预期现象:输出应当能和你手上的变更记录对上号。如果出现“文件修改时间很近,但最近没人提过变更单”的条目,就把它标出来,进入下一步判读,先别删。

盘点完立刻留一份基线快照,放到本机之外(堡垒机、日志平台或运维仓库)。之后排查时,直接 diff 基线即可定位新增内容:

mkdir -p /root/audit && cd /root/audit
tar czf cron-$(date +%F).tar.gz /etc/crontab /etc/cron.d /etc/cron.*/ /var/spool/cron 2>/dev/null
sha256sum cron-$(date +%F).tar.gz > cron-$(date +%F).sha256
lsattr -R /etc/cron.d /etc/crontab > cron-attrs-$(date +%F).txt 2>/dev/null

注意 lsattr 那一步:如果发现某个 cron 相关文件已经带着 i 属性,而你的变更记录里没有这一笔,说明之前有人(或某个程序)已经锁过,需要先查清来源再谈后续操作。

二、判读:业务任务与异常任务的区分依据

凭“看着奇怪”下结论,误删业务任务是这类巡检最常见的事故。可靠的判据是三条同时成立:有明确归属人、有可追溯的变更来源、命令链落到可信路径。

先做一轮关键词筛选,把可疑条目缩到十几条以内再看细节。这只是筛查,不是结论:

grep -REn "wget|curl|base64|/dev/tcp|nc |ncat|bash -i|python -c|perl -e|chmod +x|/tmp/|/dev/shm|@reboot" 
  /etc/crontab /etc/cron.d /etc/cron.*/ /var/spool/cron/ 2>/dev/null
特征业务任务的常见形态需要进一步核实的形态
命令来源指向 /usr/local/bin、/opt/应用目录 下的自有脚本一段内联的 `curl ...
网络行为明确的内网备份地址、对象存储域名陌生公网 IP、非常用端口、/dev/tcp/ 直连
执行频率每天、每小时、每 5 至 15 分钟每分钟一次的高频任务,或只写 @reboot
路径与权限绝对路径,属主为 root 或应用账号,权限规整藏在 /tmp、/dev/shm、.cache 之类目录,文件名带点或伪装成系统名
可维护性有注释、有日志输出、纳入了配置管理无注释、无日志,或与同名业务任务并存但内容不同
副作用产出可核对的备份、报表、清理结果只做“保活”、反复改写自身或其他 cron 文件

判定为可疑但不确定的条目,处理顺序是:先注释掉(在行首加 # 并写上日期和操作人),保留原文件备份,观察一到两个周期。直接删除会丢掉溯源线索,也可能在没弄清依赖前打断业务。

还有一种情况要单独提:cron 条目本身看起来正常,但它调用的脚本内容被换过。所以盘点不能只看 cron 文件,凡是 cron 调用的脚本,都要核对一次属主、权限和修改时间。

三、小步锁定:chattr +i 的适用边界

chattr +i 给文件加上 immutable 属性后,包括 root 在内的任何账号在不解锁的情况下都无法修改、重命名或删除它。它适合当“止血”和“防回归”手段,不适合当清除手段——已经写进去的恶意条目不会因此消失,正在运行的进程也不会因此停止。

先明确几个前提:

  • 需要 root 权限,且文件系统要支持该属性(ext4、xfs 支持;部分网络文件系统行为不同),以 lsattr 的实际输出为准。
  • 给目录加 i 会阻止在该目录内新建、重命名、删除文件,但不会阻止修改目录内已有文件的内容。要保护文件本身,得对文件单独加锁。
  • 锁定会挡住合法的变更。crontab -e 在用户 crontab 被锁后会写入失败,软件包安装往 /etc/cron.daily 投放脚本时也会失败。这些都不是故障,而是预期行为,但必须写进变更流程。

建议的锁定范围按下表控制,从变更频率最低的对象开始,一次只锁一类:

对象变更频率建议说明
/etc/crontab低可以锁系统级总表,改动少,收益直接
/etc/cron.d/ 下单个业务条目低可以锁(文件级)优先锁具体文件,先别锁整个目录
/etc/cron.d/ 目录低谨慎目录锁会挡住新增片段,装软件前需临时解锁
/etc/cron.daily 等 run-parts 目录中不建议长期锁logrotate、证书续期、索引更新等包管理动作会写入
/var/spool/cron/root中谨慎锁后 crontab -e 失效,需配套解锁流程
/etc/anacrontab低视发行版确认无包管理写入后再锁

单文件锁定的操作与验证:

# 1. 记录锁定前状态,便于回滚比对
lsattr /etc/crontab /etc/cron.d/* 2>/dev/null | tee /root/audit/before-lock.txt

# 2. 备份
cp -a /etc/crontab /root/audit/crontab.$(date +%F).bak

# 3. 加锁
chattr +i /etc/crontab

# 4. 确认属性已生效(应看到 i 标志)
lsattr /etc/crontab

预期现象:lsattr 输出的属性位中出现 i;此后任何写入该文件的尝试都会返回 Operation not permitted。锁完不要马上锁第二个对象,先走完下一节的验证。

四、变更与回滚清单

把每次锁定当成一次正式变更来对待,清单越短越容易执行到位。

变更前:

  • 已导出基线快照与 lsattr 记录,并存放到本机之外。
  • 已确认目标文件当前的 cron 条目全部能对应到业务或系统组件。
  • 已确认没有正在进行的安全处置需要临时改写该文件。
  • 已通知相关业务负责人本次变更的观察窗口。

变更中:

  • 每次只锁一个对象,锁完立刻 lsattr 复核。
  • 在变更记录里写下锁定时间、对象、执行人、解锁条件。

回滚动作(按需执行,先解锁再改内容,改完视情况重新锁定):

chattr -i /etc/crontab              # 单文件解锁
chattr -i /etc/cron.d               # 目录解锁
chattr -i /var/spool/cron/root      # 用户 crontab 解锁

# 校验是否已恢复可写
lsattr /etc/crontab
touch /etc/crontab.test 2>/dev/null || true

如果回滚后仍然写不进去,先看 lsattr 是否还有残留属性,再确认文件系统是否只读、是否被 SELinux 上下文或挂载选项限制。

五、验证:锁完业务是否照常

验证要覆盖三个层面:cron 守护进程还在正常调度、任务确实按点执行了、业务功能没有被间接影响。

先看调度日志,确认没有因为文件不可写而报错:

# Debian/Ubuntu
journalctl -u cron --since "-24h" --no-pager | grep -i -E "cron|error" | tail -50
# RHEL/CentOS
journalctl -u crond --since "-24h" --no-pager | tail -50
grep CRON /var/log/cron 2>/dev/null | tail -50

正常现象是日志里能看到 (root) CMD (...) 之类的执行记录。如果出现与权限相关的错误反复刷屏,说明锁定挡住了某个仍在尝试写入的进程,需要先查清是谁在写。

再看任务的实际产出,这比日志更可信:

验证项方法期望结果
备份任务查看备份目录最新文件的时间戳与体积时间在本周期内,体积无明显异常
站点可用性访问首页、登录后台、上传一个小文件状态码正常,无 5xx,上传成功
证书续期certbot renew --dry-run(如使用 certbot)演练通过,未报 cron 相关错误
日志轮转logrotate -d /etc/logrotate.conf调试输出无致命错误
用户 crontab 可写性用被测账号执行 crontab -e 后直接退出若已锁定,应明确报错;这是预期,记录在案

观察窗口按最低频任务的一个完整周期来定:小时级任务看 2 小时以上,每日任务至少看满 24 小时,每周任务建议看满 7 天。窗口内不要叠加其他 cron 相关变更,否则出问题无法归因。

上锁的文件柜与旁边的检查清单,象征受控的文件保护

六、复盘:把一次性巡检变成常态基线

锁定只是最后一步,真正降低风险的,是让计划任务的变化始终可见。

  • 把基线快照纳入固定流程,每周重新生成一次并比对差异;差异项必须有对应变更单才能关闭。
  • 用 auditd 监控关键路径的写入事件,把改动留痕:auditctl -w /etc/cron.d -p wa -k cron_change,并把 /etc/crontab、/var/spool/cron 一并纳入。规则要写进持久化配置,重启后仍生效。
  • 把“cron 变更需先解锁、变更后重新锁定并验证”写进运维手册,避免下一个人直接对锁定的文件执行 crontab -e 后误判为系统故障。
  • 记住 chattr +i 的定位:它提高的是篡改成本,不是不可逾越的屏障——有 root 权限的人依然可以解锁。它必须和日志监控、文件完整性校验、最小权限账号管理一起用,才构成完整的防护。

最后留一条判断准则:任何一次锁定,如果说不清“锁的是哪个文件、谁会因此改不了、出问题怎么在五分钟内解锁”,就先不要锁,回去把范围缩小到单个文件再动手。

 
枫少@KillBoy
    • 晨光旧语
      晨光旧语 1

      crontab -l 真的不够,cron.d 也得过一遍

    匿名

    发表评论

    匿名网友

    拖动滑块以完成验证