Linux应急基础排查技巧

本文主要面向安全运营人员、运维人员、应急响应服务交付人员,介绍当Linux服务器失陷后如何开展应急响应排查,包括网络、进程、权限维持、文件、用户等、日志方面排查方法。

01 网络排查

已建立的网络连接排查

首先应该排查已建立的网络连接,可能服务器上存在后门程序通过反向连接攻击者C2服务器被攻击者持续控制,推荐优先采用ss命令,部分老版本Linux发行版可采用netstat命令,用法如下:

# 查看已经建立的TCP连接
ss -natulp state established
netstat -natlp | grep ESTA

如下图,存在和192.168.66.104:444端口创建的网络连接,该连接为msf的反向连接

下图为端口扫描特征,一个进程和外部大量IP和端口存在建立连接:

开放端口

查看开放端口有助于了解服务器存在哪些服务,这些服务可能是攻击者的入口,可以为后续溯源提供排查方向。可以使用ss/netstat查看开放端口,用法如下:

netstat -nautlp | grep LISTEN
ss -natulp | grep LISTEN

如下图为某服务器端口开放情况,从下图信息可知22、80、443、8080、10000端口均对外开放,其中80、443端口为nginx开放端口,其他绑定到本地环回的端口可能被反向代理从而间接开放,服务器可能失陷的原因为ssh被成功暴力破解登录或web应用存在漏洞:

02 进程排查

进程异常是最常见的主机被入侵痕迹之一,常见异常现象包括资源占用过高、进程存在异常外连、进程路径异常。

进程资源占用排查

可以通过top命令按 CPU 和内存占用排序排查进程资源占用,并记录进程ID。常用快捷键:

快捷键

作用

M

按内存占用排序

P

按CPU占用排序

d

设置刷新时间

k

结束进程

以下为top命令输出实例:

如果怀疑服务器感染挖矿病毒、卡顿,可以优先排查资源占用情况。

注:库文件劫持、rootkit可能隐藏或篡改服务器信息,但这两种情况不在本文介绍范围中

进程路径排查

根据进程ID排查进程可执行文件路径

如果通过前期通过网络连接排查到异常进程,并获取到进程ID,可以根据进程ID获取进程可执行文件路径:

/proc/[pid]/exe

可以通过以下命令排查进程更多信息,例如执行命令时所在目录:

ls -al /proc/[pid]

排查所有进程可执行路径

通过以下命令列出所有进程ID、命令、参数、文件路径,重点关注异常路径下的进程,比如/tmp、各隐藏目录等:

ps -eo pid,comm,args,exe

如下,观察到一个进程在/tmp目录下,高度可疑:

如果某些版本ps不支持exe参数,使用:

ps -eo pid,comm,args | while read pid comm args; do
  case "$pid" in
    PID|''|[0-9]*) : ;;
    *) continue ;;
  esac
  exe=$(readlink -f /proc/$pid/exe 2>/dev/null || echo '-')
  printf '%s\t%s\t%s\t%s\n' "$pid" "$comm" "$exe" "$args"
done

排查进程执行树

如果该Linux发行版使用systemd,可以通过以下命令查看进程相关信息:

systemctl status [进程ID]

如果系统有pstree,也可以通过以下方式获取执行树信息:

ps -ef

如果什么都没有,使用以下命令创建脚本,通过遍历/proc目录树获取进程信息:

cat > ./proc_ancestors << 'EOF'
#!/bin/bash
pid=${1:-$$}
while [ "$pid" -gt 0 ] && [ -d /proc/$pid ]; do
  ppid=$(awk -F'\t' '/^PPid:/{print $2}' /proc/$pid/status)
  exe=$(readlink -f /proc/$pid/exe 2>/dev/null || echo '-')
  cmd=$(tr '\0' ' ' </proc/$pid/cmdline 2>/dev/null)
  printf 'PID=%-6s PPID=%-6s EXE=%-30s CMD=%s\n' "$pid" "$ppid" "$exe" "$cmd"
  pid=$ppid
done
EOF

chmod +x ./proc_ancestors

执行:

./proc_ancestors [pid]

如下所示,从下往上是进程的树状关系:

其他进程排查技巧

# 搜索指定进程pid
pgrep [进程名一部分]
# 查看文件被删除但仍在运行的进程
lsof +L1 | grep ' txt ' | grep -vE ' (mem|DEL)'

异常进程处置

# 结束某个进程
kill -9 [完整进程名]

# 结束某个程序的所有进程
killall [程序名]

# 批量结束firefox相关进程
kill -9 $(pgrep firefox)

03 权限维持排查

攻击者如果想要长期控制一台服务器,会采用一些权限维持手法来启用后门程序,常见的权限维持手法包括:登录即执行、开机自启、定时触发。

Shell 环境配置脚本

攻击者通过在 shell 配置文件中植入后门,实现用户登录时自动执行:

~/.bashrc
/etc/bashrc
/etc/bash.bashrc

文件名

作用范围

主要作用与描述

~/.bashrc

用户级

当前登录用户专属的配置文件,用于定义个人环境变量、别名、Shell函数和自定义脚本提示符等

/etc/bashrc

系统级

为所有用户提供全局的Bash Shell设置,通常包含系统范围的别名和函数,常见于RHEL、CentOS、Fedora等系统

/etc/bash.bashrc

系统级

功能同/etc/bashrc,为所有用户提供全局设置,常见于Debian、Ubuntu及其衍生版等系统

通过以下命令可以遍历所有用户.bashrc文件,通过less命令进行查看:

for user in $(cat /etc/passwd | cut -d: -f1);do echo "###/home/$user/.bashrc###";sudo cat /home/$user/.bashrc 2>/dev/null ;done | less

通过以下命令可以查看全局bashrc文件:

cat /etc/bashrc /etc/bash.bashrc

通过以下命令可以在所有用户bashrc文件检索特定字符串:

for user in $(cat /etc/passwd | cut -d: -f1);do echo "========/home/$user/.bashrc========";sudo grep -rn [要检索的字符串] /home/$user/.bashrc 2>/dev/null ;done

例如检索恶意文件名msf_66.104_4444.elf字符串,检索到在 /home/ops/.bashrc文件的第7行存在:

用户环境初始化配置文件

用户登录系统时会自动执行几个 profile 脚本文件,用于会话初始化操作,如设置环境变量、启动程序、定义别名和函数。攻击者可能将后门程序写入这些 profile 中以进行权限维持:


~/.profile
~/.bash_profile
/etc/profile

文件名

作用范围

主要作用与描述

触发时机

/etc/profile

系统级

为所有用户提供全局的登录Shell配置,系统管理员在这里设置全局环境变量(如PATH、JAVA_HOME)和启动脚本

用户登录系统时(仅一次)

~/.bash_profile

用户级

当前登录用户专属的登录Shell配置文件,用于设置个人环境变量和启动程序,常见于RHEL、CentOS、Fedora等系统

用户登录系统时(仅一次)

~/.profile

用户级

功能类似~/.bash_profile,为当前用户设置登录环境,常见于Debian、Ubuntu及其衍生版等系统,更符合POSIX标准

用户登录系统时(仅一次)

排查方法和前面一致,不再贴示例图,以下是常用命令:


# 查看所有用户.profile
for user in $(cat /etc/passwd | cut -d: -f1);do echo "###/home/$user/.profile###";sudo cat /home/$user/.profile 2>/dev/null ;done

# 查看全局profile
cat /etc/profile

# 在所有用户.profile中检索指定字符串
for user in $(cat /etc/passwd | cut -d: -f1);do sudo grep -rn 【要检索的字符串】 /home/$user/.profile /home/$user/.bash_profile 2>/dev/null ;done

# 示例:在所有用户profile中检索msf字符串
for user in $(cat /etc/passwd | cut -d: -f1);do sudo grep -rn msf /home/$user/.profile /home/$user/.bash_profile 2>/dev/null ;done

自启动服务和初始化脚本

当前主流 Linux 发行版采用 systemd 管理服务,可以通过 systemctl 对开机自启动服务进行排查:

systemctl list-unit-files | grep enabled

部分老旧系统采用 System V init 和 Upstart 管理服务,所以相关路径都需要进行排查:

# 需要排查的路径
/etc/systemd/system/
/etc/inittab
/usr/lib/systemd/system/
/etc/init/
/etc/rc.d/
/etc/rc.local

初始化系统

典型发行版

核心配置文件/目录

系统初始化脚本

用户自定义启动方式

System V init

CentOS 6、RHEL 6、Debian 7及更早版本

/etc/inittab

/etc/rc.d/rc.sysinit

/etc/rc.local

systemd

CentOS 7+/RHEL 7+、Ubuntu 16.04+、Debian 8+(现代主流发行版)

/etc/systemd/system/、/usr/lib/systemd/system/

systemd-sysinit.service

自定义.service文件

Upstart

Ubuntu 9.10至14.10、CentOS 6

/etc/init/(.conf文件)

rc-sysinit.conf

/etc/rc.local或自定义Upstart任务

# 在服务相关路径中搜索指定字符串
grep -rn "字符串" /etc/systemd/system/* /etc/inittab /usr/lib/systemd/system/* /etc/init/* /etc/rc.d/* /etc/rc.local

计划任务

# 通过crontab命令查看计划任务(不推荐,容易遗漏)
crontab -l              # 列出当前用户计划任务详细内容
crontab -l -u user      # 列出指定用户计划任务

需要注意的是,如果计划任务中包含\r (回车符), 会导致 crontab -l 输出时覆盖前面的内容,导致crontab -l输出不可见,所以计划任务排查建议通过 find 命令手动查看以下位置的计划任务:

/var/spool/cron/*
/var/spool/anacron/*
/etc/crontab
/etc/cron.d/*
/etc/cron.daily/*
/etc/cron.hourly/*
/etc/cron.monthly/*
/etc/cron.weekly/*
/etc/anacrontab

可以通过以下命令查看所有计划任务:

( \
  echo "===== /etc/crontab ====="; cat /etc/crontab 2>/dev/null; \
  echo -e "\n===== /etc/anacrontab ====="; cat /etc/anacrontab 2>/dev/null; \
  echo -e "\n===== /var/spool/cron ====="; \
  for f in /var/spool/cron/*; do [ -f "$f" ] && echo -e "\n--- $f ---" && cat "$f"; done; \
  echo -e "\n===== /var/spool/anacron ====="; \
  for f in /var/spool/anacron/*; do [ -f "$f" ] && echo -e "\n--- $f ---" && cat "$f"; done; \
  echo -e "\n===== /etc/cron.d ====="; \
  for f in /etc/cron.d/*; do [ -f "$f" ] && echo -e "\n--- $f ---" && cat "$f"; done; \
  echo -e "\n===== /etc/cron.hourly ====="; ls -l /etc/cron.hourly/ 2>/dev/null; \
  echo -e "\n===== /etc/cron.daily ====="; ls -l /etc/cron.daily/ 2>/dev/null; \
  echo -e "\n===== /etc/cron.weekly ====="; ls -l /etc/cron.weekly/ 2>/dev/null; \
  echo -e "\n===== /etc/cron.monthly ====="; ls -l /etc/cron.monthly/ 2>/dev/null; \
)

或者使用 grep -rn在这些计划任务目录和文件检索指定字符串:

grep -rn "[检索字符串]" /var/spool/cron/ /var/spool/anacron/ /etc/crontab /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.monthly/ /etc/cron.weekly/ /etc/anacrontab

恶意计划任务处置

确认恶意计划任务后的处置方式:

# 使用编辑器编辑当前的crontab文件
crontab -e
  
# 删除指定计划任务
sed -i '/str/d' file
  
# 删除所有计划任务(谨慎操作)
crontab -r

# vim 编辑计划任务文件
vim [计划任务文件]

04 文件排查

可执行程序排查

新版本find命令支持 -executable 参数,可以使用以下命令进行排查

# 排查近期修改的可执行程序
find [目录列表] -type f -executable -mtime -1 -exec ls -l {} \; 2>/dev/null

这里只用/tmp目录做演示,可以看到成功排查出刻意放置的文件:

老版本可以使用下面命令进行检索(兼容性高,新版本一样可以使用)

find [目录列表] -type f -mtime -7 \( -perm -u=x -o -perm -g=x -o -perm -o=x \)

排查某文件状态

可以使用 stat 命令排查文件状态,包括修改时间

stat [filename]

排查某时间段修改文件排查

# 排查指定时间范围内被修改过的文件
find [路径列表] -type f -newermt '2026-08-21 08:00:00' ! -newermt '2026-08-22 17:00:00' 2>/dev/null
  
# 排查某时间范围的文件(按修改时间排序,最新在前)
find [路径列表] -type f -newermt '2026-08-21 08:00:00' ! -newermt '2026-08-22 17:00:00' -printf "%T@ %Tc %p\n" | sort -nr

find 命令时间参数说明:

  • %T@:文件的最后修改时间(mtime),以Unix时间戳(秒+小数部分)表示,如1689456789.123456789
  • %Tc:文件的最后修改时间,格式化为可读的日期时间,如Mon Jul 17 14:33:09 2023
  • %p:文件的完整路径

文件完整性排查

部分病毒程序会修改或替换 netstat、ps、top 等常见系统命令,以实现权限维持或回显信息隐藏。对比文件 MD5 值和修改时间,主要有两种方式。

第一种使用 md5sum 校验关键文件,并将 MD5 值放到威胁情报平台检索或者与正常同版本软件包文件对比:

md5sum [文件]

如果系统是RPM系,可以使用rpm -Va 检测(RPM 系):

rpm -Va

该命令本质上也是对比文件的 MD5 值,校验时取本地文件的 MD5 值,然后和库里面的值进行校验,如果有改变则判断为变化,则会有标志位。

输出参数含义:

标志

含义

S

文件长度发生了变化

M

文件的访问权限或文件类型发生了变化

5

MD5校验和发生了变化

D

设备节点的属性发生了变化

L

文件的符号链接发生了变化

U

文件/子目录/设备节点的owner发生了变化

G

文件/子目录/设备节点的group发生了变化

T

文件最后一次的修改时间发生了变化

05 用户排查

用户信息排查

账户排查

# 查看所有账户
cat /etc/passwd | cut -d: -f1
  
# 查看超级用户(UID为0的用户)
awk -F: '$3==0 {print $1}' /etc/passwd

发现多个异常账户:

账户登录失败排查

排查近期登录失败信息:

lastb

可以看到192.168.66.105短时间内多次登录root账户失败,疑似暴力破解:

所有用户最后一次登录时间排查

查看所有用户最后的登录信息,如果有异常用户登录信息,则可以给大致入侵时间提供参考:

lastlog

当前用户

排查当前用户近期登录,看是否有陌生IP或者异常时间的登录记录:

last  # 数据来自/var/log/wtmp、/var/log/btmp、/var/log/utmp

空口令账户排查

# 查看空口令账户
awk -F: '$2==0 {print $1}' /etc/shadow

公钥登录排查

将 SSH 公钥写入用户家目录下的 .ssh/authorized_keys 文件中可无需密码登录服务器,攻击者可能写入自己的公钥实现对服务器的长期访问:

# SSH公钥排查
ls -al /root/.ssh/
cat /root/.ssh/authorized_keys

# 排查所有用户公钥写入情况
for user in $(cat /etc/passwd | cut -d: -f1);do echo "========/home/$user/.ssh/authorized_keys========";sudo cat /home/$user/.ssh/authorized_keys 2>/dev/null ;done

用户管理

# 切换账户
su
  
# 锁定账户(解锁用-u)
passwd -l user
  
# 删除账号
userdel [用户名]

06 日志排查

历史命令排查

以下主要针对 bash,服务器也极少使用其他 shell:

# 历史下载的脚本(通过wget/curl下载的后缀为.sh/.pl/.py的脚本)
more /root/.bash_history | grep -E "((wget|curl).*\.(sh|pl|py))" | grep -v grep
  
# 历史增加的账号
history | egrep "(useradd|groupadd)" | grep -v grep
  
# 历史是否删除过账号
history | egrep "(userdel|groupdel)" | grep -v grep
  
# 查看所有用户所有类型shell的可疑命令执行记录
sudo find /home /root -type f \( -name ".bash_history" -o -name ".zsh_history" -o -name ".sh_history" -o -name ".history" -o -path "*/.local/share/fish/fish_history" \) -exec echo -e "\n===== {} =====\n" \; -exec sh -c 'cat {} | grep -E "curl|useradd|userdel|whoami|ifconfig|vim|sh|python|wget|frp|kill" | grep -v grep' \;

其他常见 shell 命令历史记录文件名:

  • .sh_history(ksh)
  • .history(csh)
  • .bash_history(bash)
  • .zsh_history(zsh)

身份认证和授权日志分析

身份验证和授权相关日志存储在 /var/log/secure 和 /var/log/auth.log 中,这两个文件在功能上完全相同:

  • RHEL/CentOS/Fedora/Rocky Linux/AlmaLinux 等基于 Red Hat 的发行版使用 /var/log/secure
  • Debian/Ubuntu/Linux Mint 等基于 Debian 的发行版使用 /var/log/auth.log
# 查看SSH登录成功日志
grep -E "Accepted (password|publickey)" /var/log/secure* /var/log/auth*
  
# 查看SSH登录失败日志
grep "Failed password" /var/log/secure* /var/log/auth*
  
# 查看新增用户
grep "new user" /var/log/secure* /var/log/auth* | awk -F '[=,]' '{print $1,$2}' | awk '{print $1,$2,$3,$9}'

查看定时下载任务

计划任务日志存储在 /var/log/cron 开头的文件中,可以结合 grep 进行筛选:

more /var/log/cron* | grep "wget\|curl"