在Ubuntu服务器安全运维中,SUID(Set User ID)文件是最容易被攻击者利用的后门载体之一。所谓SUID文件,就是权限位中带有"s"标识的可执行文件,普通用户运行它时会以文件所有者(通常是root)的权限执行。如果系统中存在异常的SUID文件,攻击者就能轻松提权。最直接的防御手段就是用cron定时任务自动扫描、记录并告警SUID文件的变化,同时配合权限审计脚本对关键文件进行定期核查。下面直接给出完整的实施方案。
一、为什么必须定期检查SUID文件
Ubuntu系统默认会自带一些合法的SUID文件,比如/usr/bin/passwd、/usr/bin/sudo、/usr/bin/pkexec等,这些是系统正常运行所需的。但问题在于,如果有人通过漏洞上传了恶意程序并设置了SUID位,或者某个软件包更新时引入了不该有的SUID文件,系统就会出现隐蔽的提权通道。手动检查不现实,服务器少则几十台,多则上千台,必须自动化。cron就是Linux下最可靠的定时执行工具,配合脚本可以实现7×24小时无人值守监控。
二、快速查看当前系统SUID文件清单
在写脚本之前,先手动跑一次命令看看现状。打开终端执行以下命令:
find / -type f -perm -4000 -exec ls -l {} \; 2>/dev/null
这条命令会从根目录开始查找所有带有SUID位(4000)的文件,并列出详细权限信息。正常的Ubuntu 22.04系统大约有30到50个SUID文件。如果你发现数量突然激增,或者出现了/tmp、/var/tmp、/dev/shm等临时目录下的SUID文件,那基本可以判定系统已经被入侵。
三、编写SUID检查与审计脚本
下面是一个生产级别的Shell脚本,它会完成三件事:扫描SUID文件、对比上次记录发现新增或删除、检查关键系统文件的权限是否被篡改。将以下内容保存为/usr/local/bin/suid_audit.sh:
#!/bin/bash
# Ubuntu SUID文件定期审计脚本
# 作者:安全运维实践
# 用途:cron定时调用,检测SUID异常与权限变更
LOG_DIR="/var/log/suid_audit"
REPORT_FILE="$LOG_DIR/suid_report_$(date +%Y%m%d_%H%M%S).txt"
PREV_FILE="$LOG_DIR/suid_baseline.txt"
ALERT_EMAIL="admin@example.com"
KEY_FILES=(
"/usr/bin/passwd"
"/usr/bin/sudo"
"/usr/bin/pkexec"
"/usr/bin/newgrp"
"/usr/bin/chsh"
"/usr/bin/chfn"
"/usr/bin/gpasswd"
"/usr/bin/mount"
"/usr/bin/umount"
"/usr/bin/su"
"/bin/ping"
"/bin/ping6"
"/usr/bin/at"
"/usr/bin/crontab"
)
mkdir -p "$LOG_DIR"
echo "=== SUID Audit Report - $(date '+%Y-%m-%d %H:%M:%S') ===" > "$REPORT_FILE"
# 1. 扫描当前所有SUID文件
echo "[*] Scanning SUID files..." >> "$REPORT_FILE"
find / -type f -perm -4000 -exec ls -l {} \; 2>/dev/null | sort -k9 >> "$REPORT_FILE"
# 2. 对比基线文件,发现新增或删除
if [ -f "$PREV_FILE" ]; then
echo "[*] Comparing with previous baseline..." >> "$REPORT_FILE"
diff "$PREV_FILE" <(find / -type f -perm -4000 -exec ls -l {} \; 2>/dev/null | sort -k9) >> "$REPORT_FILE" 2>&1
if [ $? -ne 0 ]; then
echo "[!] WARNING: SUID files have changed since last check!" >> "$REPORT_FILE"
fi
else
echo "[*] First run, saving baseline..." >> "$REPORT_FILE"
find / -type f -perm -4000 -exec ls -l {} \; 2>/dev/null | sort -k9 > "$PREV_FILE"
fi
# 3. 检查关键文件权限
echo "[*] Checking critical file permissions..." >> "$REPORT_FILE"
for f in "${KEY_FILES[@]}"; do
if [ -f "$f" ]; then
perms=$(stat -c "%a %n" "$f")
echo " $perms" >> "$REPORT_FILE"
else
echo "[!] MISSING: $f" >> "$REPORT_FILE"
fi
done
# 4. 检查临时目录是否有SUID文件(高风险信号)
echo "[*] Checking temporary directories for SUID files..." >> "$REPORT_FILE"
for dir in /tmp /var/tmp /dev/shm /run; do
count=$(find "$dir" -type f -perm -4000 2>/dev/null | wc -l)
if [ "$count" -gt 0 ]; then
echo "[!] CRITICAL: Found $count SUID file(s) in $dir" >> "$REPORT_FILE"
find "$dir" -type f -perm -4000 -exec ls -l {} \; 2>/dev/null >> "$REPORT_FILE"
fi
done
echo "[*] Audit complete. Report saved to $REPORT_FILE"
# 5. 如果有变更则发送告警
if [ -f "$PREV_FILE" ]; then
diff "$PREV_FILE" <(find / -type f -perm -4000 -exec ls -l {} \; 2>/dev/null | sort -k9) > /dev/null 2>&1
if [ $? -ne 0 ]; then
mail -s "SUID Audit Alert - $(hostname)" "$ALERT_EMAIL" < "$REPORT_FILE"
fi
fi
给脚本加上执行权限:
chmod 700 /usr/local/bin/suid_audit.sh
四、配置cron定时任务
脚本写好了,接下来让它定时跑。用root用户编辑crontab:
sudo crontab -e
在文件末尾添加以下内容:
# 每天凌晨2点执行SUID审计 0 2 * * * /usr/local/bin/suid_audit.sh # 每6小时额外检查一次临时目录SUID文件 0 */6 * * * find /tmp /var/tmp /dev/shm -type f -perm -4000 2>/dev/null | mail -s "Emergency SUID Check - $(hostname)" admin@example.com
第一条是主任务,每天凌晨2点完整扫描并生成报告。第二条是快速检查,每6小时扫一遍临时目录,一旦发现异常立即发邮件告警。如果你的服务器数量多,建议把报告统一汇总到一台日志服务器上,用rsync或者日志转发工具集中管理。
五、扩展权限审计:不只是SUID
SUID只是权限审计的一部分。真正完整的安全检查还应该包括SGID(Set Group ID)文件、全局可写文件、不属于任何包的文件等。可以在脚本里追加以下检查段:
# 检查SGID文件
echo "[*] Scanning SGID files..." >> "$REPORT_FILE"
find / -type f -perm -2000 -exec ls -l {} \; 2>/dev/null | sort -k9 >> "$REPORT_FILE"
# 检查全局可写文件(任何人都能修改的文件)
echo "[*] Scanning world-writable files..." >> "$REPORT_FILE"
find / -type f -perm -0002 -exec ls -l {} \; 2>/dev/null | sort -k9 >> "$REPORT_FILE"
# 检查/etc/passwd和/etc/shadow权限
echo "[*] Checking /etc/passwd and /etc/shadow permissions..." >> "$REPORT_FILE"
ls -l /etc/passwd /etc/shadow /etc/group /etc/gshadow >> "$REPORT_FILE"
特别注意/etc/passwd和/etc/shadow的权限,正常应该是644和600或者000(取决于shadow是否独立)。如果被改成了777或者其他可写权限,说明有人动过手脚。
六、利用包管理器验证文件归属
一个很实用的技巧是用dpkg验证SUID文件是否属于合法软件包。如果某个SUID文件不属于任何已安装的包,那它就是"孤儿文件",风险极高。可以在脚本中加入:
# 检查SUID文件是否属于合法包
echo "[*] Verifying SUID file ownership via dpkg..." >> "$REPORT_FILE"
find / -type f -perm -4000 2>/dev/null | while read f; do
pkg=$(dpkg -S "$f" 2>/dev/null | cut -d: -f1)
if [ -z "$pkg" ]; then
echo "[!] ORPHAN SUID: $f (not owned by any package)" >> "$REPORT_FILE"
fi
done
这段代码会遍历所有SUID文件,用dpkg -S查询它属于哪个包。查不到的就标记为孤儿文件,直接写入告警报告。
七、日志管理与告警优化
审计报告会越积越多,必须做日志轮转。创建/etc/logrotate.d/suid_audit配置:
/var/log/suid_audit/*.txt {
daily
rotate 30
compress
delaycompress
missingok
notifempty
}
这样报告保留30天,超过自动压缩。如果你用了集中日志系统,可以把报告路径改成网络共享目录或者直接通过syslog转发。告警邮件建议配置成发送到运维群组,而不是个人邮箱,避免单点故障。
八、实战经验与注意事项
第一,首次运行脚本时会生成基线文件,之后每次对比都以这个基线为准。如果系统做了大版本升级或者大量安装软件,基线会失效,需要手动删除/var/log/suid_audit/suid_baseline.txt让脚本重新生成。第二,find命令扫描全盘比较耗资源,如果服务器负载高,可以把扫描范围缩小到关键分区,或者用ionice降低I/O优先级。第三,不要忽略容器环境,Docker和LXC容器里的SUID文件同样需要监控,可以在宿主机上对容器镜像和运行时文件系统做定期检查。第四,脚本里的告警邮箱一定要测试能正常收发,很多运维配了告警但从来没收到过,等于白配。
九、总结
Ubuntu安全不是装完系统就完事的,SUID文件监控是最基础也是最有效的主动防御手段之一。通过cron定时执行审计脚本,配合基线对比、孤儿文件检测、关键权限核查和日志轮转,可以构建一套低成本高可靠的安全监控体系。核心思路就是:自动化发现、快速告警、持续追踪。把这套方案部署到每一台Ubuntu服务器上,你的安全基线就稳了一大半。
