接手一台陌生的Linux服务器,我做的第一件事从来不是装什么花哨的监控面板,而是先把手头这几个安全命令过一遍。系统有没有被入侵、有没有异常账号、有没有可疑进程在和外网通信,其实几条命令就能看出大概。很多朋友问我“服务器被黑了怎么办”,我都会反问一句:你平时有没有定期跑过这些排查命令?如果连服务器现在是谁在登录、哪些端口在监听都不清楚,那等出事再补救,成本就完全不一样了。
这篇文章我把日常排查和加固时最常用的一批Linux安全命令整理成了一条完整链路,从账号审计、文件权限、进程网络,到防火墙和日志监控,每一段都带着实操思路和判断方法。适合刚接触服务器运维的新手,也适合已有一定经验、想建立一套标准化排查流程的从业者。文章里所有命令我都按“为什么要跑、跑完怎么看、异常怎么处理”的顺序来讲,你完全可以照着敲一遍,把输出结果和自己机器上的状态对照起来看。
1. 账号与认证:第一道门先看谁站在门口
1.1 登录记录里藏着的“夜行者”
排查安全问题的第一步,永远先看谁登录过这台机器。
code复制last -a | head -50
lastb -a | head -20
last读取的是/var/log/wtmp,能列出所有成功登录的记录,包括登录用户、来源IP、登录时间、持续时间。lastb对应的是/var/log/btmp,记录的是所有失败的登录尝试。这两份日志配合起来看,基本能判断“有没有人成功闯进来过,或者正在疯狂猜密码”。
我拿到一台机器时,习惯先看lastb里有没有大量来自同一个IP的记录。如果某个IP在短时间内成百上千次尝试登录,几乎可以肯定是爆破行为。这里有个坑:lastb里的记录可能已经被攻击者清掉,所以不要单独依赖它。更稳妥的做法是配合journalctl查SSH服务的登录日志:
code复制journalctl _COMM=sshd --since "7 days ago" | grep "Accepted"
这条命令能列出最近7天所有SSH成功登录的会话。我后来排查“有没有后门账号登录过”时,靠的就是它——因为很多攻击者清理日志时只删了wtmp和btmp,journald里的记录反而容易被漏掉。
顺着登录记录往下走,还要看看现在有哪些人和哪些会话在线:
code复制w
who -u
w的输出比who更详细,能看到每个登录用户当前执行的命令。如果在输出里看到一个陌生的用户名,或者某个人的负载特别高、TTY可疑,那就要当成重点对象盯下去。
1.2 用户与组:多出来的id要当回事
登录记录正常,不代表账号体系安全。检查系统里所有用户,是排查后门的核心环节。
code复制awk -F: '$3==0{print $1" uid="$3" "$7}' /etc/passwd
getent passwd | awk -F: '$3>=1000{print $1" uid="$3}'
cat /etc/sudoers | grep -v "^#" | grep -v "^$"
第一条命令是查UID为0的账号。Linux里UID 0就是root权限,攻击者如果创建了一个普通用户再把UID改成0,这个账号登录后拿到的是完全的超级用户权限,而你在/etc/passwd里可能只会看到一个不起眼的名字。按惯例,除了root之外,系统里不应该再出现UID 0的账号,一旦出现就要高度警惕,确认它是否真的是自己创建的。
第二条命令列出手动创建的用户(通常UID从1000开始),用来核对每一个账号的产生时间、用途和登录Shell。如果某个账号Shell是/bin/bash但从来没换过密码,或者你在记录里根本想不起来什么时候建过它,那就要考虑是不是被种了后门账号。
/etc/sudoers也得翻。见过一些案例,攻击者给某个普通用户加了一行ALL=(ALL) NOPASSWD:ALL,之后每次入侵都用那个普通用户登录,执行命令时直接sudo到root,连密码都不用猜。检查sudoers时重点看有没有NOPASSWD、有没有不知名的用户名。
1.3 认证侧的几个加固动作
排查出异常账号只是开始,把认证体系加固到位才能避免下一次被轻易进来。
先处理密码策略:
code复制chage -l 用户名 # 查看某个用户的密码过期信息
chage -M 90 用户名 # 设置密码90天后必须更换
passwd -l 用户名 # 锁定一个不再使用的账号
passwd -l这个操作在退役账号时特别实用。比如团队里有人离职了,账号一时半会不能删,那就先锁掉,避免有人拿着人家的密码继续登录。注意锁定操作不会断开当前已登录的会话,真要处理得配合pkill -u 用户名一起踢下线。
SSH服务端的几个参数也非常关键。打开/etc/ssh/sshd_config,至少确认这几项:
code复制PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
PermitRootLogin no禁止root直接SSH登录,PasswordAuthentication no关掉密码登录,只允许密钥认证。这两项配合起来,爆破难度会提高一个量级。因为我见过太多用root+弱密码直接被扫到的机器,关掉之后至少能挡掉90%的自动化攻击。
这里要给个提醒:改SSH配置前先检查当前是否有密钥能登录,改完一定要先开一个新会话验证没问题再断旧会话。有次我在一个远程机器上改了PasswordAuthentication no,结果发现私钥不在手里,差点把自己锁在门外。这种操作最稳妥的做法是保留一个已连接的会话别断开,确认新配置能登录成功后再关闭它。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 文件与权限:把后门藏身地翻一遍
2.1 大文件、新文件与隐藏目录
账号没问题,接下来要确认系统里有没有被上传的可疑文件。攻击者落地文件时通常会放在几个固定位置:临时目录、系统目录里的隐藏目录、Web目录,或者某个高权限用户的家目录。
找最近几天被修改过的文件是最直接的突破口:
code复制find / -mtime -7 -type f \( -name "*.sh" -o -name "*.pl" -o -name "*.py" \) 2>/dev/null | grep -vE "^/(proc|sys|dev)"
这条命令会在全盘范围内找出7天内新增或修改过的脚本文件,并排除虚拟文件系统。跑出来的结果里如果混着/tmp/x.sh、/var/tmp/...这类路径,就得很仔细地去看了。实际排查时我见过有人把挖矿脚本放在/tmp/.X11-unix这种隐藏目录下,不扫根本发现不了。
隐藏目录本身也是重点。Linux下以点开头的目录不会出现在普通ls里,攻击者特别喜欢这类位置:
code复制find / -type d -name ".*" -not -path "/proc/*" 2>/dev/null | head -100
看到名字特别像系统组件但你完全不认识的目录,进去翻一下。比如某些恶意脚本会在/usr/lib/.systemd/这类路径下存放核心文件,因为系统管理员很少会去考古/usr/lib里每个子目录。
找大文件也是一个思路。异常进程的日志文件、挖矿程序下载的压缩包,体积通常不会太小:
code复制find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null | sort -k5 -h
2.2 SUID/SGID 特殊权限排查
SUID和SGID是Linux里极其容易被忽略的后门载体。一个带SUID权限的程序在执行时,会以文件所有者的身份运行。如果攻击者把一个Shell复制到某个目录并给它加上SUID权限,你只要执行那个文件,就能直接获得root权限。
排查命令:
code复制find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
-4000表示SUID位,-2000表示SGID位。跑完之后对照一下系统里本就应该带SUID的程序清单,比如/usr/bin/passwd、/usr/bin/sudo、/bin/mount、/usr/bin/su。如果出现了/tmp/xx、/var/tmp/xx、或者某个用户家目录下的程序,十有八九是后门。
这里还有个判断误区:光看文件时间戳不够。攻击者做过时间伪造的情况我遇到过不止一次,文件mtime显示两年前,实际是刚放的。更靠谱的办法是先用ls -l看时间和所有者,再用rpm -V或dpkg -V校验系统包文件。被篡改过的系统文件会显示出异常,具体校验方法在第4章统一讲。
2.3 文件完整性校验与计划任务检查
文件完整性校验的核心是“留底”。拿一台干净系统做一次性快照,把关键目录的哈希值存起来,后续定期比对就能发现哪些文件被动过。最轻量的做法:
code复制find /etc -type f -exec md5sum {} \; > /root/etc_baseline.md5
md5sum -c /root/etc_baseline.md5 > /root/check_result.txt 2>&1
生产环境我会直接上AIDE这类专门工具,但如果你不想装额外软件,上面这个手动基线也够用。注意基线文件本身要放到安全的地方,最好存到另一台机器上,否则攻击者可以连基线一起改。
计划任务是另一个隐藏恶意行为的常用位置。Linux下的计划任务分散在多处,不能只看crontab -l。
code复制crontab -l
cat /etc/crontab
ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/
systemctl list-timers --all | head -30
我见过的最典型的案例:/etc/cron.d/下多了一个名为update的文件,内容是一行每分钟执行一次的下载命令,下载完的脚本会自动运行再自我删除。如果不看/etc/cron.d,只查crontab -l,这种计划任务根本不会暴露。
检查计划任务时重点看三件事:一是文件里有没有wget/curl下载后执行的行为,二是执行路径是不是系统常规目录,三是owner是不是root。出现不认识的任务别急着删,先把内容备份一份,再追溯是谁在什么时候加上去的,避免误删导致业务异常。
3. 进程与网络:谁在偷偷和外面对话
3.1 进程视角揪出伪装程序
用户和文件侧排查完,就该看正在运行的东西了。安全排查里,进程排查和网络排查必须放一起做,因为一个可疑进程往往对应一条对外连接。
先看整体概况:
code复制ps aux --sort=-%cpu | head -20
top -b -n 1 | head -30
CPU占用最高的前几个进程,基本就是排查的重点范围。挖矿病毒在这类输出里非常扎眼,因为CPU占用往往是几百甚至上千。但只盯着CPU就太片面了,很多后门程序平时CPU占用很低,或者伪装成系统进程运行。遇到不认识的进程名,第一反应先去看它的可执行文件路径:
code复制ls -l /proc/PID/exe
cat /proc/PID/cmdline | tr '\0' ' '
/proc/PID/exe是进程可执行文件的真实路径符号链接。如果进程名是kworker,但exe指向/tmp/xxx,基本可以断定是伪装。cmdline能看到进程启动时的完整参数,有时启动参数里直接带着恶意下载地址或矿池地址。
进程排查时还容易忽略“名为系统进程实为替代品”的情况。比如攻击者把恶意程序命名为systemd放在/usr/bin/下,跟正常的/usr/lib/systemd/systemd路径不一致。所以排查进程一定要习惯看exe路径,而不是只认进程名。
3.2 网络连接与外联可疑IP
网络连接排查配合进程排查,能直接定位“谁在连谁”。
code复制ss -antp | head -50
ss -lnp
第一条命令列出所有TCP连接和对应的进程PID/名称,重点看ESTABLISHED状态的外联连接。第二条命令查看当前监听端口。很多后门程序会在服务器上开启一个自定义端口,等攻击者连回来。
判断异常连接时,我会顺手统计一下每个外部IP的连接数:
code复制ss -antp | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -10
输出里如果某个IP的连接数异常高,很有可能是被爆破或者主动外联。这时候再结合进程信息看看到底是谁发起的连接,就清楚了。
还有一个容易被忽略的地方:DNS查询。某些恶意程序会定期向域名发送查询来确认C2服务器地址,光看TCP连接看不到。想看DNS层行为,可以用tcpdump抓包或者查看系统缓存:
code复制tcpdump -i eth0 -n port 53 -c 100
生产环境抓包要考虑权限和流量开销,一般只在已经发现线索、需要进一步确认时再做。
3.3 日志联动定位可疑行为
进程和网络状态只能说明“当下有什么”,日志则能还原“之前发生了什么”。
判断一台机器是不是被入侵,我最常翻的日志顺序是:
code复制dmesg | grep -i fail
journalctl --since "24 hours ago" | grep -i error
tail -200 /var/log/messages
grep -i "session opened" /var/log/auth.log 2>/dev/null || journalctl _COMM=sshd
日志排查的核心目标是“建立时间线”,也就是把异常账号创建时间、可疑文件落地时间、异常进程启动时间、外联连接起始时间串在一起。比如某个用户的sudo日志显示半夜三点执行过useradd,紧接着系统里多了一个账号,那基本可以确认这是入侵痕迹。
日志操作里有几个经验值得说。一是不要盲目清空日志,即使日志里有大量重复错误,也先归档再处理,因为后续溯源全靠它。二是/var/log/auth.log(Debian系)和/var/log/secure(RedHat系)的文件名不一样,跨发行版排查时要先确认日志路径。三是日志目录的权限同样需要检查,/var/log目录如果普通用户可写,攻击者可以往里面塞伪造日志或者直接删日志,排查时要留意目录权限是否被改过。
4. 加固与监控:把该关的门都关上
4.1 防火墙与SELinux/AppArmor基础
排查完异常,接下来是日常加固。防火墙是第一道防线,原则很简单:默认拒绝,按需放行。
CentOS/RHEL系用firewalld,Debian/Ubuntu系现在也常用ufw。以firewalld为例:
code复制systemctl enable --now firewalld
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 service name=ssh accept'
firewall-cmd --reload
这段配置的作用是:移除SSH服务的全局放行规则(也就是默认关掉SSH对所有人开放),再添加一个只允许内网某网段访问SSH的规则。如果你经常需要从家里连接服务器,就把家里的固定IP写进去。没有固定IP的话,至少把密码登录关掉再开SSH,后面靠密钥认证扛着。
SELinux和AppArmor这两个强制访问控制模块,很多时候被嫌麻烦直接关掉。我现在的观点是:至少在生产环境启用enforcing或者permissive模式,并记录违反策略的日志。
code复制getenforce
setenforce 1
setenforce 1临时切换到 enforcing 模式,重启后失效。如果你怕影响业务,可以先在permissive模式下跑几天,等日志里没有新的拒绝记录了,再正式切换。完全关闭SELinux会让系统失去一层重要的纵深防御,不推荐这么干。
4.2 系统更新与软件包审计
有太多服务器被入侵是因为某个软件包存在已知漏洞而没打补丁。保持系统更新是安全里最基础也最有效的一步。
code复制yum update -y # CentOS/RHEL系
apt update && apt upgrade -y # Debian/Ubuntu系
如果需要控制变更窗口,不执行全量更新,也要至少更新涉及远程服务和内核的安全补丁。更新前先看更新列表,确认变更内容,再决定执行方式。
软件包审计的重点是发现“多出来的东西”。攻击者有时会直接通过包管理器安装工具(比如nmap、tcpdump),或者替换掉原有软件包。用包管理器自带的一致性校验,能发现被篡改的系统文件:
code复制rpm -Va | grep -E "^(S|M|5)" # CentOS系,S/M/5分别对应文件大小、权限、校验和变化
dpkg -V 2>/dev/null | grep -v "^$" # Debian系
rpm -Va的输出会显示所有与安装记录不一致的文件。正常情况会有少量配置文件变更,比如/etc/ssh/sshd_config你自己改过,这不算异常。但如果/usr/bin/ps、/usr/bin/ls这类基础命令输出校验和变化,那就非常危险了——攻击者可能替换了系统工具,用来在平时隐藏自己的进程和文件。
4.3 日志策略与简易入侵检测
日志不仅要留,还要轮转合理,防止把磁盘写满。默认的logrotate配置多半够用,关键是检查一下有没有把SSH日志、认证日志纳入轮转范围。看一眼配置:
code复制cat /etc/logrotate.d/syslog
更进一步的思路是做文件监控。Linux下最简单的做法是用auditd给关键目录加规则,一旦有写入行为就记录日志:
code复制auditctl -w /etc/passwd -p wa -k user_account_change
auditctl -w /etc/crontab -p wa -k cron_change
这两条规则分别监控/etc/passwd和/etc/crontab的写入与属性变更。之后如果有人改动了这些文件,日志会打上user_account_change和cron_change的标签,查看时一条命令就能过滤出来:
code复制ausearch -k user_account_change --start recent
如果连审计工具都不想装,也可以用最朴素的inotifywait脚本做文件变更监控。但这类常驻进程的方式要注意内存和文件句柄的占用,监控目录别铺太广,挑/etc下最关键的几个文件即可。
日志集中采集属于更高阶的玩法,生产环境建议至少做到每天把/var/log目录同步到独立存储或另一台机器上。就算攻击者清掉了本机日志,你依然能拿着备份做溯源。这个步骤并不需要搭建多么复杂的日志系统,写个定时rsync任务也能解决一大部分问题。
5. 常见问题速查与一套完整的排查顺序
5.1 高频问题速查表
| 现象 | 可能原因 | 一条命令确认 |
|---|---|---|
| 服务器CPU莫名飙高 | 挖矿程序在跑 | ps aux --sort=-%cpu | head |
| 发现陌生用户登录 | 后门账号存在 | last -a + awk -F: '$3==0' /etc/passwd |
| 某个端口对公网开放 | 服务未限制来源IP | ss -lnp 查看对应进程 |
| 系统运行缓慢且外联频繁 | 存在感染型恶意程序 | ss -antp 配合ls -l /proc/PID/exe |
| 文件被篡改或丢失 | 入侵行为或程序Bug | rpm -Va / dpkg -V |
实际排查中很多问题都是叠加出现的。比如挖矿程序往往同时体现在“CPU异常”“外联异常”“计划任务异常”三条线索上。看到CPU飙高的第一反应应该是把所有线索汇总,而不是只处理CPU这个表象。
5.2 动手排查时的标准顺序
按我常年使用且验证过效率较高的顺序,遇到安全告警时按以下步骤走:
- 先看账号和登录记录,确认当下和管理入口状态。
last -a、w、journalctl _COMM=sshd。 - 再查计划任务和文件改动,确认系统里是否有可疑任务和落地文件。
crontab -l、find / -mtime -7 -type f。 - 接着看进程和网络连接,确认当前活跃的恶意行为。
ps aux、ss -antp。 - 然后比对日志建立时间线,确认入侵路径和波及范围。
ausearch、journalctl --since。 - 最后加固和清理,按前文思路修改认证策略、配置防火墙、核查文件完整性,再决定要不要保留现场。
这个顺序的核心逻辑是“先控制局面,再追溯原因”。我见过有人一上来就删文件、杀进程,结果攻击者已经通过另一个后门重新进来,删了等于没删。正确的做法是先确认清楚了,再动手清理。
5.3 几条踩过坑才换来的经验
我早期处理过一次服务器失陷,跑了半天排查才发现后门藏在/usr/lib/systemd/system/下的一个服务单元文件里,每次开机都会自启。排查时我看了进程、看了网络连接,却漏了systemctl list-unit-files这个检查步骤。现在执行系统性排查时,我会额外跑一道:
code复制systemctl list-unit-files --state=enabled | grep -iE "tmp|update|http"
同时,日常安全不是“出了问题再上线做一遍”就结束了。命令是死的,流程是活的。我给自己定的节奏是每两周做一次快速巡检,账号、进程、网络、日志各花几分钟,结果只看变化项是否合理。这套习惯养成了,真正出现问题时你才会有“哪里不对劲”的敏锐嗅觉。
还有一点非常重要:排查过程中每一步操作都要留记录。敲过的命令、查过的日志起始位置、发现异常文件的时间点,全部写下来。前面已经讲到过,真正做溯源时,哪怕少了一条时间线记录,可能都要多花好几个小时反复翻日志。顺手记几行字,后面省下的时间远超你的想象。
安全排查这件事,说穿了就是“看得多、看得细、能坚持”。工具和命令永远只是载体,持之以恒的检查习惯才是真正的防线。
