CentOS服务器上的定时任务(Cron)常被运维人员当作“设置一次就忘掉”的组件,但安全审计中暴露出的提权路径、隐藏后门和配置漂移,多数都藏在这些周期性执行的脚本里。核查定时任务不能只盯着/var/spool/cron目录看,还要把系统级cron、用户级cron、at任务以及systemd timer一并纳入检查范围。攻击者一旦拿到低权限shell,最先翻看的往往就是/etc/crontab、/etc/cron.d、/etc/cron.hourly这些位置,因为这里面的脚本通常以root身份运行,且很少被日常巡检覆盖。

先给出一个可直接落地的核查起点:用一条命令把当前系统中所有会被周期性执行的入口全部列出来。不要只执行crontab -l,那只能看到当前用户的任务。要分别检查/etc/crontab、/etc/cron.d/下的每个文件、/etc/cron.daily/、/etc/cron.hourly/、/etc/cron.weekly/、/etc/cron.monthly/目录,以及/var/spool/cron/下每个用户对应的文件。对于systemd timer,执行systemctl list-timers --all查看是否存在非系统自带的timer单元。把这些输出汇总后,再逐条判断执行路径、执行用户和脚本内容是否可信。

核查系统级cron配置中的异常条目

/etc/crontab是系统级定时任务的主配置文件,它的格式比用户cron多一列“执行用户”。攻击者常在这里追加一条以root身份执行反向连接或下载器的任务。核查时重点看是否有指向/tmp、/dev/shm、/var/tmp等可写目录的脚本路径,是否有curl、wget、bash -i、python -c等敏感命令。下面这条命令可以快速过滤出包含网络操作或shell执行特征的条目:

grep -E 'curl|wget|bash|sh -c|python|perl|nc |/tmp|/dev/shm' /etc/crontab /etc/cron.d/* 2>/dev/null

如果输出中有你不认识的脚本名或路径,立即查看该文件的内容和权限。一个常见的后门手法是:在/etc/cron.hourly/下放一个名为sync的脚本,内容为下载并执行远程payload,文件名伪装成系统命令。核查这类目录时,不仅要看文件名,还要用file命令确认文件类型,用ls -l确认权限和属主。正常的系统脚本通常是root:root且权限为755,如果出现其他属主或可被低权限用户写入的脚本,就是高危信号。

用户级cron任务的权限与内容核查

/var/spool/cron/目录下每个以用户名命名的文件对应用户的crontab。核查时先列出所有存在cron任务的用户:

ls -l /var/spool/cron/

然后逐个查看内容。重点关注两点:一是任务中是否包含绝对路径指向用户家目录下的脚本,而这些脚本的权限是否允许被其他用户修改;二是任务中是否使用了环境变量重定义,比如修改PATH或SHELL变量,使命令解析指向恶意程序。攻击者在拿到普通用户权限后,如果发现该用户有cron任务且脚本可写,就会在脚本中追加提权代码,等待root或其他高权限用户触发执行。

对于脚本可写性的检查,可以用find命令找出属主与cron执行用户不一致、或组权限和其他用户权限中包含写权限的脚本文件:

find /home /opt /usr/local/bin -type f -perm /022 -exec ls -l {} \; 2>/dev/null

这条命令会列出所有组用户或其他用户可写的文件。如果其中某个文件恰好被cron调用,就需要立即修正权限或审查内容。一个更隐蔽的情况是脚本本身不可写,但脚本所在目录可写,攻击者可以删除原脚本后替换为同名恶意文件。因此目录权限的核查同样重要。

at任务与一次性调度任务的排查

很多安全人员只关注cron,却忽略了at命令创建的一次性定时任务。at任务存储在/var/spool/at/目录下,攻击者可以用它来执行一次延迟的恶意操作,避开常规的cron检查。核查方法是列出该目录下所有文件,并查看是否有非root用户创建的任务:

ls -l /var/spool/at/ && for f in /var/spool/at/*; do echo "== $f =="; cat "$f" 2>/dev/null; done

同时检查/etc/at.allow和/etc/at.deny文件,确认哪些用户被允许或禁止使用at。如果at.deny不存在而at.allow为空,意味着所有用户都可以使用at,这在多用户服务器上是一个需要收紧的配置。建议在安全基线中明确只允许root和指定的运维账号使用at,其余用户全部拒绝。

systemd timer的隐藏风险

CentOS 7及以上版本中,systemd timer逐渐替代了一部分cron功能。攻击者如果具备root权限,可以创建一个看似正常的service单元和一个timer单元,实现持久化执行。核查时除了systemctl list-timers --all,还要检查/etc/systemd/system/和/usr/lib/systemd/system/下是否存在自定义的timer文件。重点看timer触发的service是否调用了可疑的ExecStart命令,以及service文件是否被设置为开机自启。

一个容易被忽视的细节是:systemd service单元中的ExecStart可以使用相对路径或环境变量,如果PATH被篡改,实际执行的二进制文件可能并非系统原版。核查时用systemctl cat查看单元完整内容,确认ExecStart使用的是绝对路径,并且该路径下的文件属主和权限正常。

定时任务脚本内容的深度审查

只看cron条目本身不够,必须对每条任务实际调用的脚本内容进行审查。对于Shell脚本,重点检查是否存在以下模式:从网络下载文件并执行、向外部地址回传数据、修改用户密码或SSH配置、添加计划任务或自启动项、加载内核模块、修改文件属性隐藏自身。可以用grep批量扫描脚本中的敏感关键字:

grep -RlE 'curl|wget|nc |socat|base64 -d|eval|exec|useradd|passwd|iptables|chattr|rm -rf' /etc/cron* /var/spool/cron/ /opt/*/bin/ 2>/dev/null

对于Python或Perl脚本,还要检查是否有import socket、subprocess、os.system等调用,以及是否包含经过编码或混淆的字符串。攻击者常用base64编码来绕过简单的关键字匹配,所以对包含长串乱码或编码字符的脚本要保持高度警惕。如果脚本内容无法读懂,最稳妥的做法是将其隔离并还原执行逻辑,或者直接禁用该任务并观察系统行为。

建立定时任务变更监控与审批流程

核查是一次性的,管控是持续性的。对于生产环境中的CentOS服务器,建议通过文件完整性监控工具(如AIDE、Tripwire或自研的inotify脚本)对/etc/crontab、/etc/cron.d/、/var/spool/cron/、/etc/systemd/system/等关键路径进行实时监控。一旦检测到文件新增、修改或删除,立即触发告警并通知安全管理员。监控规则要覆盖文件内容变化和文件属性变化,尤其是属主和权限的变更。

在运维流程层面,应要求所有定时任务的创建和修改必须经过变更审批。审批记录中要包含任务用途、执行用户、执行频率、脚本路径和脚本内容摘要。对于临时添加的调试任务,必须设置明确的失效时间,到期自动删除。很多安全事故的根源就是临时任务忘记删除,最终被攻击者利用。

最小权限原则在定时任务中的应用

很多运维人员习惯把所有定时任务都放在root下执行,这是非常危险的做法。应该根据任务的实际需求,为不同类型的任务创建独立的低权限系统账号。例如,备份任务使用backup用户,日志清理使用logclean用户,应用重启使用appadmin用户。这些账号的shell设置为/sbin/nologin,且只授予完成任务所需的最小文件权限。即使某个脚本被篡改,攻击者获得的也只是低权限账号,无法直接控制整个系统。

对于确实需要root权限的任务,应尽量缩小脚本中root权限的作用范围。可以使用sudo配合精确的命令白名单,让低权限用户只能执行特定的命令。例如在sudoers中配置:

backup ALL=(root) NOPASSWD: /usr/bin/rsync --server *

这样即使backup用户的cron任务被篡改,攻击者也只能通过sudo执行rsync相关命令,无法直接获得完整的root shell。这种细粒度的权限控制比单纯依赖cron的属主设置要可靠得多。

环境变量与路径劫持的防御

cron任务执行时的环境变量与交互式shell不同,PATH通常只有/usr/bin和/bin。但攻击者可以通过在crontab文件中设置PATH变量来改变命令解析路径。核查时要确认每条cron任务中是否显式定义了PATH,以及这个PATH中是否包含可被低权限用户写入的目录。建议在所有cron脚本的第一行显式设置安全的PATH:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

同时,脚本中调用命令时尽量使用绝对路径,避免依赖PATH解析。对于脚本中引用的外部程序,可以用which命令确认其实际路径,并在脚本中写死。这能有效防止攻击者通过在可写目录中放置同名恶意程序来实现路径劫持。

日志记录与审计追踪

cron默认会通过syslog记录任务执行的开始和结束,但日志中不包含脚本的具体输出。为了便于事后审计,建议在每个关键cron脚本中增加日志输出,将执行时间、执行用户、脚本名称和关键操作结果写入独立的日志文件。例如在脚本开头加入:

exec 1>>/var/log/cron-task/$(basename $0).log 2>&1
echo "[$(date '+%F %T')] Script started by $(whoami)"

这样每次执行都会留下可追踪的记录。同时要确保日志目录的权限设置正确,只允许root和特定的审计账号读取,防止攻击者篡改或删除日志。对于systemd timer触发的服务,可以通过journalctl -u <unit名称>查看详细日志,并在service单元中配置StandardOutput=append:文件路径来持久化输出。

安全核查不是一次性的项目,而是需要嵌入日常运维的持续动作。建议每月至少执行一次完整的定时任务清单比对,每季度进行一次脚本内容深度审查,同时配合文件完整性监控和变更审批流程,才能把CentOS服务器上定时任务带来的风险控制在可接受范围内。真正有效的管控不是靠某一条命令或某一个工具,而是靠“清单化核查+自动化监控+流程化审批”的组合体系。