Linux蓝队溯源实战:SSH爆破后门排查与攻击链还原
上周把某实训平台的蓝队溯源靶机Linux-2完整刷了一遍从收到SSH爆破告警开始到最终写出溯源报告一整条应急响应流程走下来收获比预想中大得多。做应急响应和做渗透不一样光背命令没有用你得真正坐在一台被攻陷的Linux机器前才能体会日志、进程、文件时间戳、外连地址这些碎片是怎么互相咬合、最终串成一条攻击链的。这篇就以Linux-2这个场景为例把蓝队溯源的完整排查流程掰开揉碎讲清楚内容包括第一现场信息收集、后门排查、日志关联分析、攻击路径还原以及报告怎么写。不管你是刚入门的安全运维还是想系统提升溯源能力的同学这套流程都可以直接抄作业。1. 拿到Linux-2靶机之后先搞清楚应急响应的边界1.1 场景设定这靶机到底模拟了什么攻击蓝队溯源靶机Linux-2这个场景模拟的是一台对外提供Web服务的Linux服务器失陷后的应急响应。我刷的时候环境是一台Ubuntu 20.04系统里跑着Nginx和一个PHP应用。场景给了一个告警提示某日凌晨开始出现大量来自外部IP的SSH登录失败记录随后有一次登录成功再之后服务器出现异常外联。这种设定非常典型几乎是真实企业环境里最常见的入侵剧本攻击者通过SSH弱口令爆破进入系统然后落地后门、植入计划任务、外连控制端。拿到场景后不要急着敲命令先想清楚三个问题攻击入口是什么、失陷范围有多大、攻击者留下了什么。入口决定了你从哪类日志开始查范围决定了你要排查哪些目录和进程后门决定了你能不能把痕迹清干净。这个场景的难点不在某一个环节而是要求你把这些信息全部串起来最终形成一个有依据的结论。1.2 应急响应的标准流程证据优先别急着动手很多人做应急响应的第一反应是“看见可疑进程就kill看见可疑文件就删”这个习惯非常危险。有一次我在实际项目里看到同事一上来就结束了可疑进程结果内存里的证据全丢了后面溯源完全抓瞎。正确的流程应该分成六步接到告警、核实情况、隔离取证、深入分析、清除加固、复盘报告。核实情况这一步主要是确认告警是否真实也就是先用最基础的命令看看系统当前状态判断有没有明显异常。隔离取证是承上启下的关键如果条件允许先做内存镜像、保存进程列表、保存网络连接状态这些瞬态信息一旦丢失就再也找不回来。等你把需要保存的证据都存下来了再开始深入分析。注意靶机环境里通常没有镜像条件但你也应该养成先采集存档、后操作的习惯我在下文会给出一个自动采集脚本直接把你需要的基础证据一键存下来。1.3 排查前的命令清单和注意事项蓝队溯源本质上就是“人肉查杀”你不需要多高级的工具只要把系统自带命令用熟80%的痕迹都能找出来。我通常把排查命令分成六类系统状态、用户账户、进程网络、计划任务、文件查找、日志分析。系统状态用uname -a、uptime、w用户账户用cat /etc/passwd、last、lastlog进程网络用ps、ss、lsof计划任务看crontab和/etc/cron.d文件查找用find按时间过滤日志分析重点看auth.log或secure文件。注意排查过程中尽量使用命令的绝对路径例如/bin/ps、/usr/sbin/ss而不是直接敲ps、ss。原因是有经验的攻击者会通过alias污染命令或者直接替换系统命令用绝对路径能降低被欺骗的概率。另外一个很容易被忽略的细节是排查前先看一下系统的PATH环境变量和alias配置如果发现alias里把ls、ps、netstat这类命令指向了别的路径这台机器很可能已经被植入了rootkit。2. 第一现场登录靶机后的信息收集2.1 先看系统现状判断是否真的失陷登录靶机后我的习惯是先执行一组“现状快照”命令不动任何数据只做观察。第一条是whoami和id确认当前权限第二条是uname -a确认系统内核版本排查阶段需要知道内核版本来判断是否有内核级漏洞的利用痕迹第三条是w看当前登录的用户和来源IP同时通过load average判断系统是否异常高负载。最开始我刷这个场景时一登录就发现load average很高直觉告诉我这机器很可能被拿去挖矿了。然后执行ps auxf按CPU排序果然看到一个名字看起来像系统进程、但路径在/tmp下的进程CPU占用超过200%。这个阶段不要kill进程先把这个进程的PID、父进程PID、完整命令行、可执行文件路径记下来同时立刻执行ss -anpt查看外联地址。挖矿木马几乎必然有外联记录下对端IP和端口后面分析样本时要用。这时还要执行uptime看系统开机时间和负载趋势。如果系统才启动几分钟说明可能被人重启过那么很多瞬态证据比如内存中的进程痕迹已经丢失排查策略就要偏向磁盘上的持久化文件也就是后门和计划任务。2.2 文件时间线从时间戳追踪异常文件判断一台Linux是否被入侵最快的方式不是看病毒库扫描结果而是看文件时间线。恶意文件落地的位置虽然有随机性但时间窗口通常非常集中和攻击者的入侵时间高度吻合。我常用的命令组合是这样ls -la --time-stylefull-iso /tmp /var/tmp /dev/shm find /var/www -type f -mtime -7 -ls 2/dev/null find /etc -mtime -7 -type f -ls 2/dev/null find /usr/bin /usr/sbin /bin /sbin -mtime -7 -type f -ls 2/dev/null这些目录是最常被利用的/tmp、/var/tmp、/dev/shm是可写目录很多恶意脚本直接扔在这里Web目录是webshell的落脚点/etc下出现近期修改的文件要警惕启动项和系统配置被篡改系统命令目录里出现近期替换的文件则要考虑rootkit。具体到Linux-2这个场景我在/tmp下发现了一个名为kwerps的隐藏目录里面放着三个文件一个Python脚本、一个下载的二进制文件、一个文本文件。用stat查看时间戳发现它们的创建时间集中在登录成功后的十分钟内这个时间窗口和后文要看的日志记录完全对得上。记住发现可疑文件后一定先做md5sum把哈希值记录下来再去读文件内容。哈希值既是证据也是后续在大量文件里快速检索同一样本的依据。2.3 账户与登录痕迹弄清楚谁碰过这台机器账户排查是应急响应里绝对不能跳过的一步。攻击者进入系统后为了保住权限很可能会创建新的账号或者直接修改现有账号的UID和Shell。执行以下命令进行排查awk -F: $30 {print $1, $3, $6, $7} /etc/passwd awk -F: $31000 $365534 {print $1, $3, $6, $7} /etc/passwd grep -v nologin\|/bin/false /etc/passwd第一个命令是找出所有UID为0的用户正常情况下只有root一个如果出现其他用户基本可以断定被留了后门账号。我在这台靶机里就发现了一个名为sysadmin的用户UID是0这就说明攻击者已经拿到了root权限并且创建了隐藏管理员账号。第二个命令是列出所有普通用户重点看有没有近期新增的、不该存在的账号。第三个命令则能快速找出所有拥有合法Shell的用户结合/etc/shadow里这些用户的密码修改时间来判断是否被动过。账户之后当然就是登录痕迹。last和lastlog可以看登录记录但注意如果攻击者有root权限wtmp日志是可以被清理的。所以last输出里看不到异常不代表没人进来过关键还是要结合auth.log分析SSH登录日志同时检查每个用户的authorized_keys文件这是我看这个场景时重点关注的一项。2.4 历史命令还原攻击者的操作轨迹历史命令是蓝队溯源里性价比最高的线索来源因为它直接记录了攻击者在系统里敲了什么命令。攻击者会清history但很多时候他们只会清root的history忽略了其他账号或者清了history但没清HISTFILE对应的日志所以多查几个地方总会有收获。cat /root/.bash_history cat /home/*/.bash_history我在Linux-2靶机里查到的历史命令非常有代表性大致流程是这样攻击者先用curl从一个可疑域名下载了脚本然后chmod x赋予执行权限接着把脚本移动到/tmp下的隐藏目录之后往crontab里写入了一条每分钟执行的记录最后向/root/.ssh/authorized_keys里追加了一段公钥。这几条命令串起来基本上把攻击者的行为模式勾勒出来了下载、落地、持久化、保留后门。这里有个时间点需要注意history本身是不带时间戳的你需要结合文件的时间戳和日志记录来锚定时间。比如我看到.ssh目录下的authorized_keys文件的mtime是入侵当天的凌晨而auth.log里正好有一条对应时段的成功登录记录两者一交叉时间线就清晰了。这也是我反复强调要交叉验证的原因单一证据容易被干扰多个证据互相印证才能下结论。3. 深度排查进程、网络、后门与日志3.1 进程和网络连接找出正在与外界通信的进程第一轮信息收集完成之后已经有了初步判断接下来就要深挖系统里正在运行的恶意进程和外联连接。我常用的命令是ps和ss的组合。ps -ef --forest ps auxf --sort-%cpu | head -20 ss -anpt进程树能够直观展示父子关系恶意进程通常会伪装成系统进程名来迷惑人但父子关系很难完全隐藏。比如我在靶机上看到一个伪装成kworkerd的进程乍看像正常内核线程但它的父进程PID是1启动命令行里却带着/tmp/kwerps/update.py的路径这就露馅了。内核线程不可能从/tmp下的脚本启动所以这个进程几乎可以确定为恶意。网络连接排查要重点关注ESTAB状态且对端IP为外部地址的连接。执行ss -anpt后我发现进程正在和一个198.51.100.20的IP建立TCP连接端口是4444这就是典型的外联行为。记录进程PID、本地端口、对端IP、对端端口后再进入/proc目录查细节ls -l /proc/PID/exe cat /proc/PID/cmdline | tr \0 ls -l /proc/PID/cwd cat /proc/PID/environ这些命令能让你拿到进程对应的可执行文件真实路径、完整的参数列表、工作目录以及环境变量。很多恶意脚本会用混淆参数来逃避命令行审计但/proc里的cmdline是内核提供的比ps输出更可靠。3.2 定时任务和启动项揪出持久化后门攻击者植入的进程一旦被杀如果没有持久化机制重启之后就没了所以99%的恶意程序都会想办法把自己挂进开机启动链或定时任务里。Linux下的持久化手段就那么几个地方逐一排查即可。crontab -l cat /etc/crontab ls -la /etc/cron.d/ ls -la /var/spool/cron/ cat /etc/rc.local 2/dev/null systemctl list-unit-files --typeservice | grep enabled ls -la /etc/init.d/ /etc/systemd/system/这个靶机里设置的定时任务很典型在/var/spool/cron/crontabs/root里有一条*/1 * * * * /tmp/kwerps/update.sh /dev/null 21意思是一分钟执行一次update.sh脚本配合脚本内容里的下载逻辑就是一个标准的“回连下载更新”后门。每分钟执行一次这个频率选得也很巧妙既不会像秒级任务那样暴露明显又保证了较快的指令响应速度。挖矿木马和僵尸网络程序常使用这种策略。除crontab之外还要检查/etc/rc.local和systemd服务。有些攻击者会创建一个名字看起来非常正常的systemd service比如update-system.service然后通过systemctl enable把它设置为开机自启。检查方法就是上面最后一条命令把所有enabled状态的服务列出来一条条看启动命令重点关注启动脚本路径位于/tmp、/var/tmp、/dev/shm这类目录的条目。3.3 Web目录和后门文件扫描这台靶机上有Nginx和PHP应用所以Web后门是排查重点。攻击者爆破SSH进入系统后不一定会马上放弃Web这个入口很多时候他们会顺手往Web目录里丢一个webshell留着以后从Web侧进来。即便这个场景的攻击入口是SSH检查Web目录仍然很有必要因为安全事件中经常出现“多入口”情况。我的排查思路分为三步。第一步针对文件时间找出最近七天被创建或修改的PHP文件重点看Nginx的站点根目录常见的路径是/var/www/html或/usr/share/nginx/html。第二步直接搜索Web目录内的高危函数特征grep -rn --include*.php -E eval\(|assert\(|system\(|shell_exec\(|passthru\(|base64_decode\( /var/www/html第三步是对比现有文件与备份或初始版本找出新增文件。情报显示攻击者通常会把webshell命名成和正常业务相关的文件比如img.php、upload.php、cache.php所以光看名字很难发现必须要看内容。这个靶机里我发现了一个隐藏在/var/www/html/static/images/下的PHP文件文件名是logo_2025.php目录看起来很合法但文件内容就三行代码一句话解码加执行。这种文件只要你的PHP应用目录是可写的攻击者就能通过上传功能或直接落盘的方式放进来。发现webshell后先不要急着删除把它复制出来留档同时记录文件的完整路径、md5、修改时间以及最近的访问时间后面拼接攻击时间线时要用。3.4 日志关联分析把入侵时间线串起来日志分析是整个应急响应里最核心、也最需要耐心的一步。我见过不少新手在日志面前一头雾水十几万行记录根本不知道从哪看起。我的方法是先确定“锚点时间”也就是从文件时间线和历史命令里推断出的入侵时间段然后只分析这个时间段前后的日志效率会提高非常多。Linux系统日志需要关注这几个文件cat /var/log/auth.log # Debian/Ubuntu SSH认证日志 cat /var/log/secure # CentOS/RHEL SSH认证日志 cat /var/log/syslog # 系统日志 cat /var/log/nginx/access.log # Web访问日志用grep过滤登录失败记录再统计来源IP和次数grep Failed password /var/log/auth.log | awk {print $(NF-3)} | sort | uniq -c | sort -nr | head -20这个命令可以直接看到哪几个IP在爆破次数一目了然。我在靶机上看到的结果是203.0.113.10这个IP尝试了两百多次登录时间跨度一个多小时爆破方式有字典特征用户名从admin、root、ubuntu一路试探过来。再看Accepted记录确认最终是从哪个IP、用哪个用户名、在什么时间点登录成功的入侵入口基本就锁定了。到了这一步我就把三个证据源交叉起来了auth.log里记录的成功登录时间、/tmp下恶意文件的创建时间、crontab里恶意任务的写入时间。这三个时间点完全吻合攻击路径已经非常明确。日志分析切忌“一把梭”只看一个日志就下结论多源交叉才是靠谱的。4. 溯源还原从痕迹反推攻击路径4.1 攻击入口判断爆破、漏洞利用还是Webshell到这里这台靶机的入侵手法已经比较清楚了就是SSH弱口令爆破。但我还是想强调一下判断入口的逻辑因为很多时候攻击入口不止一个。判断入口不能只看成功的登录记录还要看有没有其他痕迹。如果是Web漏洞利用日志里通常会有异常URL特征比如访问了带有id1、../../等高危特征的路径或者上传接口的请求里出现了大量HTTP 200响应。如果是SSH爆破主要证据就是auth.log里的Failed password和Accepted记录。这个场景里Web应用本身没有明显漏洞也没有Web日志里看到可疑的利用请求但Web目录里却有一个webshell我倾向于认为它是SSH攻入之后顺手丢进去的备手而不是Web漏洞利用的结果。这里分享一个交叉验证的小技巧用攻入之后的Web日志来确认有没有后续访问webshell的记录。我在nginx的access.log里查到了针对logo_2025.php的POST请求来源IP和SSH登录来源IP一致这就进一步印证了攻击者是从SSH进来后手动放下webshell的。如果你发现来源IP不一致那就要考虑是不是有多个攻击者或分发代理节点。4.2 恶意样本的快速静态分析溯源不仅要还原路径还要搞清楚恶意文件到底是什么。我这里说的是静态分析也就是在不运行样本的前提下通过文件信息、字符串、脚本逻辑来判断它的功能。拿到/tmp/kwerps下的几个文件后我依次执行了file、md5sum、stringsfile /tmp/kwerps/update.py /tmp/kwerps/update.sh /tmp/kwerps/kwerps md5sum /tmp/kwerps/* strings /tmp/kwerps/kwerps | grep -E http|\.onion|/api|socket|reconnectfile看到update.py是Python脚本update.sh是Bash脚本kwerps是一个ELF可执行文件。strings的结果里暴露了一个域名和路径看结构像是C2回连地址。打开update.py阅读后发现它做的事情是请求指定的URL下载文件保存到/tmp目录并赋予可执行权限最终通过subprocess调用它。这已经是很明显的下载器逻辑。在应急响应中对于恶意样本只需要搞清楚它的用途下载器、挖矿木马、后门、DDoS傀儡以及它的C2地址、持久化方式就足够支撑处置决策了。不需要做深度逆向除非你所在的团队有专门的样本分析能力。静态分析阶段最重要的一条原则是不要在有业务流量的环境里直接运行恶意样本先做静态分析实在需要动态分析也要在隔离环境里做。4.3 攻击者画像与身份线索蓝队溯源经常要做的一步是通过痕迹信息尽可能还原攻击者的特征这里说的画像不是“人肉搜索”而是在授权范围内用公开情报和信息确定攻击来源以便后续封禁和追踪。在靶机场景里画像主要基于三类信息IP情报、工具特征、行为习惯。IP方面我可以把203.0.113.10拿到威胁情报平台上查一下看它是否已经被标记为恶意IP归属地和历史行为可以辅助判断这是个人攻击者还是扫描机器人。工具特征方面我在历史命令里看到攻击者使用了某个特定版本的扫描工具这个工具会留下默认的用户字典和UA标识通过对比同类样本可以推断出攻击者可能使用了什么工具集。行为习惯方面攻击活动集中在凌晨两点左右计划任务设置的时间也是凌晨这通常说明攻击脚本触发了时区参数可以结合这些线索分析其大致活动时段。在做画像的时候我的建议是不要过度解读IP归属地只能说明跳板位置或主机的机房位置不能直接断言攻击者身处哪里。对靶机而言画像的目的是让你对攻击者有整体认知为入侵检测规则优化提供参考。4.4 写一份能复盘的溯源报告溯源报告是应急响应最终的交付物也是蓝队溯源靶机考核的核心成果之一。报告不需要堆砌所有命令的输出但必须逻辑闭环。我的报告结构基本固定这次Linux-2的报告也按这个模板走事件概述发现时间、告警来源、影响系统。攻击入口SSH爆破成功来源IP、用户名、爆破时间。攻击路径下载恶意脚本→写入/tmp隐藏目录→植入计划任务→写入SSH公钥→外联C2。恶意样本分析文件列表、哈希值、功能说明。关键时间线用表格展示攻击行为序列。影响评估权限情况、范围、可能的损失。处置建议封禁IP、清除计划任务和公钥、修改密码、升级认证方式。写报告的时候时间线表是点睛之笔用表格可以一目了然。这里是这次靶机场景里整理出来的时间线时间事件来源/目标证据02:11:23SSH爆破开始203.0.113.10 → 本机auth.log Failed password 记录02:47:56SSH登录成功203.0.113.10 → rootauth.log Accepted publickey02:51:12上传恶意文件至/tmp本机文件mtime与登录时间吻合02:52:30写入SSH公钥/root/.ssh/authorized_keysstat mtime key内容比对03:05:15添加定时任务crontab/var/spool/cron/root 内容03:10:44进程外联C2本机 → 198.51.100.20:4444ss -anpt 连接记录5. 复盘与排雷实战中的关键经验5.1 应急响应里最容易翻车的几个瞬间每次做应急响应我都会提醒自己以下几点是不能踩的坑也是初学者最容易出问题的地方。第一个坑是“上手就杀”。看到恶意进程就直接kill看到可疑文件就立刻删除这会破坏证据链。正确做法是先记录、先采集等你确认所有线索都已经保存了再考虑清理这个“先存后杀”的意识一定要有。第二个坑是“只信命令输出”。如果系统被植入了rootkitps命令输出的进程列表可能是伪造的netstat输出的连接也可能被过滤。处理办法是使用多层命令交叉验证比如用ps、top、lsof、/proc目录、甚至对比前后两次命令输出。一旦发现不同命令之间的结果不一致大概率是有隐藏攻击在作祟。第三个坑是“忽略历史命令和计划任务”。我遇到过不少新手查了一堆文件却漏了crontab结果清理完文件下一个周期任务又自动把恶意文件拉回来了。所以每次应急响应crontab和systemd都是必查项宁可多查也不能漏。第四个坑是“不做记录”。排查过程中没有保存原始输出最后写报告时只能凭记忆导致时间线对不上。我的习惯是把每一步关键命令的输出都重定向到文件这既是证据也是复盘材料。5.2 溯源排查清单照着做不漏项下面这张检查清单是我在做Linux应急响应时常用的实战中我会逐项打勾。建议有需要的人直接收藏这个表格做成自己的排查SOP。排查项关键命令重点关注当前登录用户w、who、users是否有异常来源IP的登录用户账户/etc/passwd、/etc/shadowUID为0的账号、近期修改的密码登录日志last、lastlog、auth.log/secureAES失败和成功记录、来源IPSSH信任关系authorized_keys文件是否有多余的公钥历史命令.bash_history、HISTFILEwget、curl、useradd、chmod等可疑命令进程状态ps auxf、top、/procCPU占用异常、路径在/tmp或/var/tmp的进程网络连接ss -anpt、lsof -i外部IP、高危端口、ESTAB的连接计划任务crontab、/etc/cron.d、/var/spool/cron不认识的脚本路径、短周期任务开机启动systemctl、rc.local、init.d启动脚本是否位于可写目录文件时间线find -mtime、stat入侵时间窗口内的新增和修改文件Web后门grep -rn高危函数eval、base64_decode、system等恶意样本file、md5sum、strings下载器、挖矿、C2回连特征5.3 快速排查脚本与效率习惯应急响应讲究的是在最短时间内锁定问题我习惯登录一台疑似失陷机器后用脚本把基础信息一次性采集下来然后再慢慢看。这里分享一个我一直用的基础采集脚本你可以把它保存成ir_collect.sh拿到排查任务后直接跑一次。#!/bin/bash OUT/tmp/ir_$(date %Y%m%d_%H%M%S) mkdir -p $OUT echo system info $OUT/system.txt uname -a $OUT/system.txt uptime $OUT/system.txt w $OUT/system.txt echo user list $OUT/users.txt awk -F: $30 || $31000 {print} /etc/passwd $OUT/users.txt echo login records $OUT/last.txt last -20 $OUT/last.txt lastlog $OUT/lastlog.txt 2/dev/null echo bash history $OUT/history.txt for h in /root/.bash_history /home/*/.bash_history; do echo ### $h $OUT/history.txt cat $h 2/dev/null $OUT/history.txt done echo crontab $OUT/crontab.txt crontab -l $OUT/crontab.txt 2/dev/null cat /etc/crontab $OUT/crontab.txt 2/dev/null cat /etc/cron.d/* $OUT/crontab.txt 2/dev/null echo network $OUT/netstat.txt ss -anpt $OUT/netstat.txt echo process $OUT/ps.txt ps -ef --forest $OUT/ps.txt echo ssh keys $OUT/ssh_keys.txt cat /root/.ssh/authorized_keys $OUT/ssh_keys.txt 2/dev/null for k in /home/*/.ssh/authorized_keys; do echo ### $k $OUT/ssh_keys.txt cat $k $OUT/ssh_keys.txt 2/dev/null done echo 采集完成结果保存在 $OUT这个脚本输出的信息足够支撑第一轮判断。效率习惯方面我再说三点第一排查过程中遇到任何可疑文件先复制一份到独立目录再执行查看命令避免因为查看而修改了文件的atime。第二尽量保持只读操作尤其在分析阶段。第三分析日志时善用时间过滤先用grep把锚点时间段内的记录抓出来再逐条看几万行日志真正有价值的可能只有几十行。这次Linux-2靶机刷完我最大的感受是应急响应到后期拼的不是工具多强而是时间线组织能力。每一个可疑文件、每一条登录记录、每一次外联都要能落到同一条时间轴上攻击路径才会清晰。还有一个我坚持了很多年的小习惯处理完一台机器我会把采集到的原始输出全部打包存档哪怕是当时判断为误报的样本也留着因为后面复盘或者和同事讨论的时候原始证据比口头结论可靠得多。下次再遇到类似场景这些存档就是你最快的参考手册。