ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

服务器被入侵怎么办?Linux应急响应排查流程详解

服务器被入侵怎么办?Linux应急响应排查流程详解 引言为什么重启一下是最糟的选择凌晨两点监控告警某台生产服务器 CPU 满载、出口带宽跑满。运维同学的第一反应往往是reboot然后发现——机器重启后一切正常了但三天后同样的告警再次出现甚至数据库被拖走。这是应急响应中最典型、也最致命的错误。Linux 系统的入侵痕迹高度依赖易失性数据内存中的进程、/proc下的文件描述符、未落盘的网络连接、被unlink但仍被进程持有的可执行文件。一次重启等于亲手销毁了 80% 的取证证据。具体来说一次reboot会永久丢失这些东西/proc下所有进程的cmdline、environ、cwd、fd符号链接ss/netstat里处于ESTABLISHED、TIME_WAIT状态的连接四元组内存中未写盘的加密密钥、反弹 Shell 的会话、被memfd_create创建的无文件恶意载荷以及仅在内存中存在的定时任务与注入代码。这些数据一旦消失你连攻击者从哪个 IP 连进来、用的是哪个进程都说不清楚更谈不上溯源。国外取证领域有一个广为接受的易失性数据顺序源自 RFC 3227《Guidelines for Evidence Collection and Archiving》寄存器与缓存 → 内存 → 网络状态 → 运行中进程 → 磁盘 → 备份与归档介质 → 打印件。本文的采集顺序与之一致只是把网络提前到了进程之前因为在实战中网络连接往往是最快能定位到 C2Command Control命令控制服务器的线索。还有一点需要提前明确不同类型的入侵排查的侧重点完全不同。挖矿类特征是 CPU/GPU 满载、外连矿池域名或 IP、落地文件常带kdevtmpfsi、kinsing、xmrig等特征名。这类攻击者追求长期稳定占用资源通常不会刻意隐藏排查相对容易。勒索类特征是文件被批量加密、留下勒索信README.txt、HOW_TO_DECRYPT。攻击者往往已经在内网横向移动多时且会主动清除日志。这类场景的第一优先级是止损与隔离而不是溯源。APT / 定向攻击特征是使用无文件技术、内存马、合法工具Living off the Land如curl、python、systemctl做后门隐蔽性极强。排查必须做完整的持久化清单核对与内存取证。跳板类攻击者只是把你的机器当代理特征是异常的外连与端口转发ssh -R、socat、frp。这类机器本身可能看起来很干净但流量特征明显。应急响应的本质不是把机器修好而是回答三个问题攻击者是谁Who、怎么进来的How、动了什么What。只有回答清楚这三个问题才能谈清除与加固。本文从实战角度给出一套可直接落地的 Linux 应急响应排查流程。一、应急响应的核心原则在动手敲命令之前先建立四条纪律断网不断电。拔掉网线或在下游交换机/安全组封禁 IP但绝不关机、不重启。这样既切断了 C2 回连和横向移动又保住了内存现场。从易失到持久。采集顺序应为内存 → 网络连接 → 进程 → 临时文件 → 磁盘文件 → 日志归档。硬盘数据最持久最后处理。先取证后清除。任何kill、rm之前先记录 PID、命令行、父进程、启动时间、对应文件哈希。不信任本机工具。入侵者常替换ps、netstat、ls、top甚至lsmod。关键结论要用静态编译的干净二进制如 busybox、自带的lsof或从只读介质挂载的工具交叉验证。这四条纪律看起来简单但在真实的高压场景下每一条都容易被违反。下面逐条展开。关于断网不断电的实操细节拔网线是最干脆的做法但要注意——如果是云主机你无法物理拔网线此时应在安全组里把出站规则全部拒绝仅保留运维跳板机的入站 22 端口。为什么要优先封出站因为横向移动和数据外传都是出站行为先断出站能立刻遏制损失扩大。而保留运维入站是因为你还需要登录进去做采集。有一种情况需要例外处理如果攻击者已经控制了你的运维跳板机那么保留 SSH 入站反而给了对方继续操作的机会。此时应该改用带外管理云厂商的 VNC、物理机的 IPMI/iDRAC登录或干脆把受害机做成镜像后在隔离环境分析。关于从易失到持久的原因进程、连接这些数据在系统运行期间一直在变。攻击者的木马可能每 30 秒重连一次 C2你多拖一分钟现场就多一分被覆盖的风险。而磁盘上的文件、日志是静态的晚一点采集影响不大。所以顺序不能颠倒。关于先取证后清除这是最反直觉的一条。运维的本能是看到恶意进程就 kill 掉但kill -9之后/proc/PID/exe这个指向恶意二进制的符号链接就消失了你再也无法提取样本、计算哈希、提交沙箱分析。正确做法是先用kill -STOP PID发送 SIGSTOP暂停进程但保留所有现场采集完成后再决定是否终止。kill -STOP还有一个好处进程被暂停后不再发起网络连接相当于软隔离比直接 kill 更安全。关于不信任本机工具用户态 rootkit 的经典手法就是替换ps、ls、netstat、find等常用命令通过过滤输出隐藏自己。例如一个被篡改的ps会在输出中跳过特定 PID。验证方法有两个一是用busybox ps这类静态编译的替代品交叉比对二是直接读/proc目录本身因为/proc是内核提供的虚拟文件系统用户态工具无法篡改其内容除非加载了内核模块。这一点在后文 3.2 节有具体命令。踩坑提示很多同学在排查时会习惯性地history一下想看看攻击者敲过什么命令。这个动作有两个问题第一攻击者通常会unset HISTFILE或history -c你看不到什么第二你自己的排查命令会被记录进history反而污染了现场。正确做法是先cp ~/.bash_history到证据目录再做分析。二、排查流程总览我习惯用两条线交叉的方式组织排查横向层次线网络 → 进程 → 账号 → 持久化 → 文件 → 内核。纵向时间线以日志中的异常登录时间T0为锚点用find -newermt把该时间点前后落地的文件全部捞出来。单一维度容易漏交叉验证才能形成完整证据链。为什么必须交叉举个例子你在横向排查中发现/etc/cron.d/里多了一个文件这属于持久化维度但只有当你用stat查看它的修改时间发现恰好等于T0才能确认它就是本次入侵的产物而不是某次运维遗留。反过来时间线维度会捞出一大堆正常文件apt更新、日志轮转必须结合层次线判断哪些是恶意的。把两条线做成一张对照表排查时逐格打钩能有效避免遗漏层次关注对象对应时间线检查网络ss、lsof -i、/proc/net连接的inode与进程启动时间比对进程ps、/proc/pid/*进程lstart是否落在T0附近账号passwd、shadow、authorized_keys文件的mtime/ctime持久化cron、systemd、ld.so.preload、rcfind -newermt T0文件/tmp、/dev/shm、Web 目录find -newermt、-mmin内核lsmod、dmesg、/sys/module模块加载时间关于T0锚点的选取T0不一定是第一次异常登录。如果攻击者是通过 Web 漏洞打进来的那么T0应该是 Web 访问日志里第一个异常请求的时间如果是 SSH 爆破进来的T0就是Accepted password/publickey那一行的时间戳。如果日志被清了退而求其次可以用异常进程的启动时间ps -o lstart或可疑文件的ctime作为近似锚点。踩坑提示find -newermt依赖文件系统的mtime而攻击者可以用touch -d伪造时间戳。所以时间线只能作为线索不能作为证据。真正可靠的证据是文件哈希、进程行为与网络流量。要识别时间戳伪造可以对比mtime内容修改时间、ctimeinode 变更时间和atime访问时间如果mtime明显早于ctime就值得怀疑。三、逐层排查实战3.1 第一层网络连接与监听端口# 查看所有连接与监听-p 显示进程-n 不做 DNS 反查ss-antup# 只看 ESTABLISHED 的外连快速定位 C2ss-antpstate established|awk{print $5, $6}|sort|uniq-c|sort-rn# 通过 /proc 交叉验证防 netstat 被替换ls-l/proc/*/exe2/dev/null|grep-ideleted重点看三类异常高位端口外连如xxx:4444、:6667IRC 僵尸网络、:3333挖矿矿池。可疑监听非业务端口的LISTEN尤其是0.0.0.0上的 22 之外的 shell 类服务。/proc/*/exe指向(deleted)文件被删除但进程仍在运行这是恶意程序删自身躲查杀的经典特征也是内存取证的最佳入口。补充几个判断经验ss -antup里的-u是 UDP很多后门尤其 DNS 隧道类走 UDP容易被忽略。awk那条命令按远端地址聚合计数如果某个外部 IP 被多个进程反复连接大概率是心跳回连。矿池连接的典型特征是目标端口固定、连接数多、流量持续但不大而反弹 Shell 的典型特征是目标端口随机、连接长时间 ESTABLISHED、流量小而规律。还可以直接读/proc/net/tcp它不依赖任何用户态工具# /proc/net/tcp 里的地址是十六进制小端序0100007F 就是 127.0.0.1cat/proc/net/tcp /proc/net/tcp6|head-20常见问题为什么ss显示连接存在但lsof -i看不到进程因为lsof需要读取/proc/pid/fd权限非 root 用户会漏掉其他用户的进程。用sudo lsof -i -n -P可解决。另一种可能是连接处于TIME_WAIT此时 socket 已无进程持有属于正常现象。踩坑提示不要只看LISTEN。很多后门比如 SSH 端口转发、socat根本不监听端口而是主动外连。只查监听会让你漏掉一大半。3.2 第二层进程与内存ps-eopid,ppid,user,lstart,etime,cmd--sortstart_timecat/proc/PID/cmdline|tr\0 cat/proc/PID/environ|tr\0\n# 常能看到矿池地址、C2 域名ls-l/proc/PID/cwd /proc/PID/exe异常进程的典型特征父进程是1被 daemon 化、命令行是随机字符串、工作目录在/tmp、/dev/shm、/var/tmp启动时间与异常登录时间吻合。如果怀疑 rootkit 隐藏进程可以对比ps与/proc目录数量ps-e--no-headers|wc-lls-d/proc/[0-9]*|wc-l两者差异明显基本可以确认存在用户态或内核态隐藏。进一步挖掘时/proc/PID/maps和/proc/PID/fd是两个金矿# 看进程加载了哪些库重点找非标准路径下的 .socat/proc/PID/maps|awk{print $6}|sort-u# 看进程打开了哪些文件能发现日志、配置、socketls-l/proc/PID/fdmaps里如果出现/tmp/xxx.so、/dev/shm/xxx.so几乎可以确定是LD_PRELOAD类的用户态劫持。fd里如果出现指向socket:[...]的条目把 inode 号拿去和ss -ae输出比对就能确认该进程的网络行为——即使ss被替换这条路径也依然可靠。常见问题ps和/proc的数量差几个正常吗正常。内核线程[kworker/*]等在/proc下也有目录但ps -e是否显示取决于ps的实现和--hide选项。通常差 3~5 个属于正常波动。稳妥做法是用ps -eLf显示线程或直接比较同名进程的可见性而不是比较总数。更可靠的做法是用busybox ps与系统ps的输出做差集。踩坑提示/proc/PID/cmdline里攻击者可以伪造命令行。例如把进程名改成[kworker/0:0]混在内核线程里。识别方法真内核线程的cmdline是空的且exe链接不存在ls -l /proc/PID/exe会报No such file or directory。如果某个内核线程却有exe指向一个真实文件那就是假的。3.3 第三层账号与登录痕迹# 检查 UID 为 0 的账号以及空口令账号awk-F:$30 {print $1}/etc/passwdawk-F:($2) {print $1}/etc/shadow# 登录记录last-a-i|head-50lastb-a|head-50# 失败登录暴力破解痕迹lastlog|grep-vNever# SSH 后门排查grep-EAuthorizedKeys|PermitRootLogin|ForceCommand/etc/ssh/sshd_configcat/root/.ssh/authorized_keysfind/-nameauthorized_keys-execls-l{}\;2/dev/null极易被忽略的一点authorized_keys里的一行公钥就是永久的免密后门。攻击者写入后即使你改了 root 密码他依然能登录。所有用户的.ssh目录都要查包括www-data、nginx这类服务账号。除了authorized_keys还有几个 SSH 相关的后门点必须查/etc/ssh/sshrc与~/.ssh/rcSSH 登录时会执行这两个脚本是典型的隐蔽持久化点。AuthorizedKeysCommandsshd_config里这个指令允许从外部命令动态获取公钥攻击者可以指向自己的脚本。/etc/passwd中的shell字段如果某个服务账号的 shell 从/sbin/nologin被改成了/bin/bash说明攻击者在给它开后门。/etc/sudoers与/etc/sudoers.d/检查是否有xxx ALL(ALL) NOPASSWD: ALL这类新增条目。PAM 模块/etc/pam.d/下被插入pam_exec.so可以记录所有明文密码这是最阴险的后门之一。常见问题last输出为空或被截断说明没问题吗不能说明。last读的是wtmp攻击者可以用utmpdump或直接写二进制文件来篡改也可以简单地把/var/log/wtmp清空。判断方法看wtmp文件的mtime和大小如果mtime与T0吻合而内容却很少基本可以确定被清过。此时应该转向journaldjournalctl _COMMsshd或云厂商的审计日志如阿里云的操作审计、AWS CloudTrail这些在宿主机层面记录攻击者通常删不掉。3.4 第四层持久化机制这是排查的重中之重。Linux 的持久化入口非常多建议逐一核对# 1. croncrontab-l;ls-la/var/spool/cron/ /var/spool/cron/crontabs/2/dev/nullgrep-rEcurl|wget|base64|/dev/tcp|bash -i/etc/cron* /var/spool/cron2/dev/null# 2. systemd现代发行版最主要的持久化方式systemctl list-units--typeservice--staterunningls-la/etc/systemd/system/ /lib/systemd/system/ ~/.config/systemd/user/2/dev/nullgrep-rEExecStart.*(tmp|shm|base64|curl)/etc/systemd/system/2/dev/null# 3. 动态链接器劫持cat/etc/ld.so.preload# 非空即高危echo$LD_PRELOAD# 4. Shell 启动脚本grep-rEcurl|wget|/dev/tcp/etc/profile /etc/bash.bashrc ~/.bashrc ~/.bash_profile2/dev/null# 5. rc.local / init.dcat/etc/rc.local2/dev/null;ls-la/etc/init.d/# 6. PAM 后门可记录明文密码ls-la/etc/pam.d/;grep-rpam_exec/etc/pam.d/2/dev/null/etc/ld.so.preload是最高危的持久化手段之一它会在几乎所有动态链接程序启动时加载指定.so攻击者借此劫持readdir隐藏文件、劫持open隐藏进程实现用户态 rootkit。上面六项只是必查项完整的持久化清单还应包括at任务atq查看一次性定时任务/var/spool/at/是存放目录。~/.bash_logout、/etc/bash.bash_logout退出时执行容易被忽略。/etc/environment、/etc/profile.d/*.sh环境变量注入点。/etc/rc*.d/、/etc/init.d/SysV 风格的启动脚本。/etc/update-motd.d/登录时显示的横幅脚本也会被执行。/etc/apt/apt.conf.d/、/etc/yum.conf包管理器的 hook可以在装包时执行任意命令。.forward与/etc/aliases邮件转发规则攻击者可以借此把邮件外传。/etc/nsswitch.conf、/etc/ld.so.conf.d/库搜索路径劫持。Git hooks如果服务器上有 Git 仓库.git/hooks/下的脚本会在commit、push时执行。容器环境/var/lib/docker/、/var/lib/kubelet/、/etc/kubernetes/下的配置以及kubelet的static pod目录。踩坑提示crontab -l只显示当前用户的 cronroot 排查时一定要加sudo -u user crontab -l逐个用户看或者直接ls /var/spool/cron/crontabs/Debian 系或/var/spool/cron/RHEL 系。另外/etc/cron.d/下的文件是系统级的格式比用户 crontab 多一列用户名容易看漏。常见问题/etc/ld.so.preload被写了但我删不掉怎么办这是典型的鸡生蛋问题因为rm命令本身也会被preload劫持攻击者可以让unlink系统调用对特定路径返回EPERM。此时应该用busybox rm或静态编译的rm或者用echo -n /etc/ld.so.preload清空内容而非删除文件再重启进入救援模式彻底清理。最稳妥的方式是直接挂载 LiveCD 从外部修改。3.5 第五层文件系统与内核# 按时间线捞文件以异常登录时间 2024-05-01 为例find/-xdev-newermt2024-05-01 00:00!-newermt2024-05-02 00:00\-typef-printf%T %p\n2/dev/null|sort# SUID/SGID 提权后门find/-xdev-perm-4000-typef-printf%m %u %p\n2/dev/null# 隐藏文件与 Web 目录后门find/var/www-typef\(-name*.php-o-name*.jsp\)\-newermt2024-05-012/dev/null# 内核模块lsmod;cat/proc/modules|head-30dmesg|grep-iEtaint|module内核层排查还可以借助auditd若已开启与chkrootkit/rkhunter做辅助判断但要注意这类工具只做模式匹配误报率高且无法发现新型 rootkit结论必须人工复核。文件系统排查有几个容易被忽略的点-xdev很重要不加它find会遍历/proc、/sys等虚拟文件系统不仅慢还会产生大量噪音。隐藏目录与文件名find / -name .* -type d可以发现.xxx形式的隐藏目录。攻击者常用..两个点加空格或.点加空格这类肉眼难辨的名字。Web 目录的时间聚集一句话木马往往集中在某个时间段落地find -newermt配合ls -lt能快速定位。还可以按文件大小排序find /var/www -type f -size -2k可以捞出体积异常的极小 PHP 文件。/tmp与/dev/shm/dev/shm是 tmpfs重启即失攻击者很喜欢。ls -la /dev/shm必查。SUID 白名单find -perm -4000的输出应该与系统默认清单比对。可以提前准备一份基线rpm -Va或dpkg -V也能校验包完整性。rpm -Va/dpkg -V这是最快发现系统文件被替换的方法。如果输出里有/usr/bin/ps、/usr/bin/netstat的校验失败几乎可以确定被 rootkit 替换了。常见问题dmesg里看到taint就是被入侵了吗不一定。dmesg里的Tainted标记可能来自非 GPL 驱动的内核模块如 NVIDIA 显卡驱动、VirtualBox 增强工具这在云主机和虚拟化环境中很常见。要结合lsmod判断如果模块名不认识、不在发行版仓库里、且加载时间与T0吻合才需要警惕。3.6 补充容器与云原生环境的特殊考量如果受害机跑着 Docker 或 Kubernetes排查思路要额外加一层# 查看所有容器注意那些不是你自己创建的dockerps-a--no-trunc# 查看容器挂载了宿主机的哪些目录提权逃逸的入口dockerinspectCONTAINER_ID|grep-A5Mounts# K8s 环境下检查所有命名空间里的 Podkubectl get pods --all-namespaces-owide# 检查 kubelet 的静态 Pod 目录攻击者常在此植入ls-la/etc/kubernetes/manifests/容器环境有两个高频风险点一是容器逃逸攻击者利用特权容器或挂载了/var/run/docker.sock的容器控制宿主机二是K8s 的 ServiceAccount Token默认挂载在/var/run/secrets/kubernetes.io/serviceaccount/泄露后可以直接调用 API Server 创建恶意 Pod。排查时如果发现宿主机上有来历不明的容器、或者kubectl里出现了陌生的ClusterRoleBinding就要高度警惕。踩坑提示容器内的/proc是宿主机/proc的子集在容器里排查进程会漏掉宿主机上的恶意进程。正确做法是进入宿主机的命名空间nsenter -t 1 -m -u -i -n -p或者直接在宿主机上排查。四、实战案例Redis 未授权 → SSH 后门 → 挖矿现象某电商后台服务器 CPU 100%top显示进程kdevtmpfsi占用 98%。处置步骤第一步隔离现场安全组封禁全部出站保留 SSH 运维白名单不重启。第二步现场采集。写一个脚本把易失数据一次性落到只读挂载的 U 盘或跳板机上避免逐条命令敲打过程中现场被污染#!/bin/bash# ir-collect.sh —— 应急现场快速采集OUT/mnt/usb/ir-$(hostname)-$(date%Y%m%d%H%M)mkdir-p$OUT/{proc,net,log,fs}# 1. 时间基准date-u$OUT/date.txt;uptime$OUT/uptime.txt# 2. 网络与进程ss-antup$OUT/net/ss.txt21lsof-i-n-P$OUT/net/lsof.txt21ps-eopid,ppid,user,lstart,etime,cmd--sortstart_time$OUT/proc/ps.txtforpin/proc/[0-9]*;dopid${p#/proc/}{echo PID$pidtr\0 $p/cmdline;echotr\0\n$p/environ2/dev/null|head-30readlink$p/exe$p/cwd}$OUT/proc/detail.txt21done# 3. 账号与登录cp/etc/passwd /etc/shadow /etc/sudoers$OUT/fs/2/dev/null last-a-i$OUT/log/last.txt;lastb-a$OUT/log/lastb.txt21cp/var/log/secure /var/log/auth.log$OUT/log/2/dev/null# 4. 持久化crontab-l$OUT/fs/crontab.txt21ls-laR/etc/systemd/system /var/spool/cron$OUT/fs/persist.txt21cat/etc/ld.so.preload$OUT/fs/ld_preload.txt21# 5. 哈希固化保证证据链完整find$OUT-typef-execsha256sum{}\;$OUT/../manifest.sha256echo[] 采集完成:$OUT这个脚本有两个设计要点值得说明。第一所有输出都重定向到文件而不是打印到终端。终端输出会被script或审计系统记录也可能被攻击者的监控进程捕获直接落盘到只读介质更安全。第二最后一步做哈希固化。sha256sum生成的清单是证据链Chain of Custody的基础它能证明我从现场带走的这份数据在分析过程中没有被修改。如果后续要走法务流程这份清单和采集时间、采集人签名一样重要。第三步日志分析定位入口。/var/log/secure里发现了大量失败登录但真正有效的是这条Accepted publickey for root from 45.x.x.x port 51234 ssh2root 从未配置过公钥登录说明攻击者已写入authorized_keys。更多硬核网安与AI工具包请扫码获取完整源码进一步回溯redis-server的日志显示攻击者用CONFIG SET dir /root/.ssh CONFIG SET
返回列表