SSH日志分析实战:从auth.log提取攻击痕迹
1. 项目概述这不是在看日志是在读服务器的“心跳记录”“玄机靶场 | 日志分析-ssh日志分析”——这行标题乍看像一道CTF练习题实则是一扇通往真实运维与安全响应核心能力的窄门。我带过十几期蓝队实训每次开课第一件事就是让学员打开/var/log/auth.log或secure盯着那些密密麻麻的sshd日志发呆。有人以为这是在查“谁连过服务器”其实远不止如此每一次Failed password、Accepted publickey、Connection closed、pam_unix(sshd:session)、systemd-logind的登录事件都是系统在用最原始的语言告诉你——此刻它正经历什么压力、遭遇何种试探、是否已被悄然渗透。这不是日志是服务器的实时心电图而SSH日志就是这张图上跳动最剧烈、最易被误读也最不容忽视的QRS波。玄机靶场之所以把SSH日志分析单列出来恰恰因为它是最“朴素”却最“锋利”的入口。相比IIS、Tomcat、MSSQL这些应用层日志SSH日志结构简单纯文本、固定字段、生成高频每秒可产生数十条、覆盖全面认证、授权、会话、登出全链路且几乎无法被应用层逻辑绕过——哪怕攻击者删了webshell只要他还用SSH维持后门auth.log里就一定留痕。你不需要懂SQL注入原理也不必研究Apache模块加载顺序只需要理解一条日志的7个核心字段时间戳、主机名、服务名sshd、进程ID、事件类型Failed password / Accepted / Connection closed、用户、来源IP及端口。这7个字段就是解码整个入侵链条的密钥。适合谁来啃这块硬骨头三类人必须掌握一是刚转行做安全运营的新人这是你脱离“点按钮式SOC平台”的第一步二是运维工程师当客户凌晨三点打电话说“服务器变慢了”你得在5分钟内判断是资源耗尽还是有人在暴力扫号三是红队成员你写的免杀后门若连SSH会话都藏不住那离被发现就不远了。我见过太多人花三天配好ELK堆栈却看不懂一条“Invalid user admin from 192.168.1.100 port 54321”背后隐藏的横向移动意图。这篇内容不讲花哨工具链只聚焦一件事如何从原始日志文本中像法医提取DNA一样精准定位异常模式、还原攻击路径、锁定失陷主机。所有操作均基于Linux原生命令轻量脚本无需安装任何第三方SIEM一台Kali或CentOS虚拟机即可复现。接下来我们直接进入实战拆解。2. 核心思路拆解为什么不用ELK因为真正的分析始于终端很多人看到“日志分析”第一反应就是搭ELKElasticsearchLogstashKibana或Graylog。这没错但对玄机靶场这类场景它反而成了障碍。我曾在某金融客户现场调试过一套ELK光是Logstash filter规则写错一个正则就导致SSH登录成功事件被误标为失败——结果安全团队连续三天误报“暴力破解成功”。问题不在ELK本身而在于过度依赖可视化界面会钝化你对原始日志语义的直觉判断力。就像医生不能只看CT影像就下结论必须结合病史和体征。SSH日志分析的第一道防线永远是人眼终端命令的组合。所以本方案采用“三层漏斗式分析法”第一层快速筛查grep/awk/sed——用正则匹配高频攻击特征如“Failed password for invalid user”、“reverse mapping checking getaddrinfo for”DNS反向解析失败常伴随扫描、“Connection closed by authenticating user”异常断连。这层目标是10秒内圈出可疑IP段。第二层时序建模sort/uniq -c——将IP时间戳组合排序统计单位时间内连接频次。暴力破解不是均匀分布的而是呈现“短时密集爆发→短暂休眠→再次爆发”的脉冲特征。单纯看单条失败日志没意义要看它是否属于某个IP的第17次尝试。第三层行为画像自定义脚本关联——把SSH日志与系统其他日志如lastlog、wtmp、/var/log/messages交叉验证。例如某IP在auth.log显示“Accepted password for root”但在lastlog里查不到该IP对应的成功登录记录——这极可能意味着攻击者清除了登录痕迹仅保留了auth.log中的“成功”假象因auth.log默认不可删除而wtmp可被篡改。这个思路的底层逻辑是日志不是孤立的数据点而是攻击者行为在时间轴上的投影。玄机靶场的题目设计往往暗含时间陷阱——比如给出一段24小时日志但关键攻击发生在凌晨3:17:22到3:17:45之间前后仅23秒。如果你只用grep搜“root”会漏掉攻击者用普通账户登录后再提权的关键过渡环节。因此所有工具选型都服务于一个原则最小化数据搬运最大化时间维度控制。awk比Python快10倍处理百万行日志tac比cat更适合倒序查最新事件journalctl --since 2024-03-15 03:17:00比任何日志平台的“时间选择器”更精准。下面我们就从最基础的日志结构开始一层层剥开它的外壳。3. SSH日志结构深度解析每一行都是一个微型犯罪现场要读懂SSH日志先得认准它的“身份证”。在绝大多数Linux发行版中CentOS/RHEL默认为/var/log/secureUbuntu/Debian为/var/log/auth.logsshd日志遵循syslog标准格式典型行如下Mar 15 03:17:22 target-server sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 54321 ssh2 Mar 15 03:17:23 target-server sshd[12346]: Connection closed by authenticating user root 192.168.1.100 port 54322 [preauth] Mar 15 03:17:24 target-server sshd[12347]: Accepted password for root from 192.168.1.100 port 54323 ssh2 Mar 15 03:17:25 target-server sshd[12348]: pam_unix(sshd:session): session opened for user root by (uid0) Mar 15 03:17:26 target-server systemd-logind[678]: New session 123 of user root.别被这堆字符吓住我们按字段逐个解剖以第一行为例Mar 15 03:17:22时间戳。注意这里没有年份且是本地时区。玄机靶场常考陷阱日志时间与系统时间不一致如NTP未同步或攻击者伪造时间戳需结合/var/log/messages中kernel时间戳交叉验证。target-server主机名。若为“localhost”或“unknown”需警惕日志被重定向或攻击者修改了/etc/hostname。sshd[12345]服务名进程PID。PID是关键线索——同一攻击会话中连续几条日志的PID通常递增如12345→12346→12347若出现跳跃12345→12350可能意味着中间有其他进程干扰或是攻击者触发了某种异常退出。Failed password for invalid user admin事件类型。这是最核心字段包含三重信息认证结果“Failed password” vs “Accepted password” vs “pam_faillock”失败锁定用户状态“invalid user”用户不存在 vs “user root”存在用户用户名“admin”——注意大小写敏感且攻击者常用admin、administrator、test等弱用户名。from 192.168.1.100 port 54321来源IP端口。IP是溯源主线索端口揭示攻击工具特征如nmap扫描常用高端口hydra默认用随机端口而Metasploit常固定用22端口。ssh2协议版本。若出现“ssh1”说明服务器仍启用不安全的SSHv1已淘汰这是严重配置缺陷。提示不要忽略空格分隔符的语义。例如“Connection closed by authenticating user root”与“Connection closed by preauth”有本质区别前者表示用户已通过认证但会话异常终止可能是主动退出或网络中断后者preauth表示认证阶段就断开了常见于暴力破解时攻击者主动放弃连接。再看一条更隐蔽的线索pam_unix(sshd:session): session opened for user root by (uid0)这行看似普通但它暴露了两个致命细节session opened表明用户已获得完整shell权限不再是preauth阶段by (uid0)暗示该会话由root用户启动即sudo su或直接root登录而非普通用户提权。若你在日志中看到普通用户登录后立即出现“session opened for root”就要立刻检查该用户是否拥有sudo权限且未设密码。最后强调一个易错点日志轮转logrotate机制。玄机靶场给的日志文件名常为auth.log.1、auth.log.2.gz很多人直接用cat打开.gz文件结果报错。正确做法是zcat auth.log.2.gz | grep Failed password。我曾见学员因不解压直接分析硬生生漏掉了前两天的关键攻击痕迹。4. 实操流程详解从原始日志到攻击画像的七步推演现在我们进入实战环节。假设你拿到玄机靶场提供的日志文件auth.log约50MB含24小时数据目标是找出所有异常登录行为并还原攻击路径。以下是我在真实红蓝对抗中验证过的七步法每一步都附带命令、原理和避坑点。4.1 第一步确认日志范围与完整性30秒先执行head -n 5 auth.log和tail -n 5 auth.log观察首尾时间是否连续。若首行为Mar 14 00:00:01尾行为Mar 14 23:59:59说明日志完整。若尾部时间突然跳到Mar 15 01:00:00则可能被截断或存在多文件拼接。此时需检查是否存在auth.log.1、auth.log.2.gz等轮转文件并用zcat auth.log.2.gz auth_full.log合并。注意不要用cat auth.log* auth_full.log因为通配符会按字母序排列auth.log.10在auth.log.2之前导致时间线错乱。正确命令是zcat auth.log.2.gz auth.log.1 auth.log | sort -k1,3 auth_full.log用sort按第1-3列月日时排序。4.2 第二步筛选高危事件2分钟用grep提取四类关键事件# 1. 无效用户暴力破解最常见 grep Failed password for invalid user auth_full.log invalid_user.log # 2. 有效用户密码爆破更危险说明字典含真实用户名 grep Failed password for user auth_full.log | grep -v invalid valid_user_fail.log # 3. 成功登录但来源可疑如非办公网段 grep Accepted password for auth_full.log | grep -E (192\.168\.|10\.|172\.1[6-9]\.|172\.2[0-9]\.|172\.3[0-1]\.) internal_accept.log # 4. 异常断连preauth阶段关闭常为扫描器特征 grep Connection closed by.*preauth auth_full.log preauth_close.log避坑点grep -v invalid不能写成grep -v invalid否则会过滤掉所有含invalid的行包括invalid user。必须加空格限定词边界。4.3 第三步IP频次统计与阈值判定5分钟对invalid_user.log中的IP进行计数awk {print $11} invalid_user.log | sort | uniq -c | sort -nr | head -20输出类似1245 192.168.1.100 876 10.0.2.5 321 172.16.0.200但1245次是否算攻击需结合时间窗口。用以下命令计算192.168.1.100在10分钟内的峰值频次grep 192.168.1.100 invalid_user.log | awk {print $1,$2,$3} | \ sed s/://g | awk {tint($3/600)*600; print $1,$2,t} | \ sort | uniq -c | sort -nr | head -5原理将时间戳秒数除以60010分钟取整得到时间块编号再统计每个块内次数。若某IP在10分钟内尝试超200次基本可判定为暴力破解。4.4 第四步时间序列关联8分钟找出192.168.1.100的完整行为链# 提取该IP所有相关日志含失败、成功、断连 grep 192.168.1.100 auth_full.log | sort -k1,3 ip_100_full.log # 查看其首次失败到最后成功的时间差 head -1 ip_100_full.log # Mar 15 03:17:22 tail -1 ip_100_full.log # Mar 15 03:17:24 # 仅2秒说明字典极小或存在漏洞利用更关键的是检查其登录后的操作# 在ip_100_full.log中找session opened之后的5行 sed -n /session opened/{N;N;N;N;p;} ip_100_full.log # 输出可能含command whoami、id、ls -la /tmp等4.5 第五步用户行为交叉验证10分钟检查root用户是否真被登录# 查lastlog中root的最后登录IP lastlog -u root | tail -1 # 若显示**Never logged in**但auth.log有Accepted for root则日志被篡改 # 查wtmp中该IP的登录记录 last -i 192.168.1.100 | grep root # 若无输出而auth.log有记录同样可疑4.6 第六步SSH配置审计5分钟检查服务器是否启用危险配置# 查PermitRootLogin状态 grep PermitRootLogin /etc/ssh/sshd_config # 若为yes且日志中有root登录风险极高 # 查PasswordAuthentication grep PasswordAuthentication /etc/ssh/sshd_config # 若为yes说明允许密码登录易受暴力破解4.7 第七步生成攻击画像报告3分钟整合所有线索输出结构化报告echo 攻击IP: 192.168.1.100 report.txt echo 总尝试次数: $(wc -l invalid_user.log) report.txt echo 首次失败: $(head -1 invalid_user.log | awk {print $1,$2,$3}) report.txt echo 首次成功: $(grep Accepted.*192.168.1.100 auth_full.log | head -1 | awk {print $1,$2,$3}) report.txt echo 时间差: $(($(date -d $(grep Accepted.*192.168.1.100 auth_full.log | head -1 | awk {print $1,$2,$3}) %s) - $(date -d $(head -1 invalid_user.log | awk {print $1,$2,$3}) %s)))秒 report.txt echo 关联命令: $(grep 192.168.1.100 auth_full.log | grep COMMAND | head -3) report.txt这份报告能直接用于撰写事件响应工单。记住分析的价值不在于找到IP而在于回答“它做了什么、用了多久、是否成功、后续影响是什么”。下面我们深入几个高频问题的排查技巧。5. 常见问题与排查技巧实录那些教科书不会写的坑在玄机靶场和真实环境中我踩过太多关于SSH日志的坑。下面分享5个最典型的“看似简单实则致命”的问题每个都附带真实案例和一招制敌的命令。5.1 问题1grep搜不到“Failed password”但日志明明有现象grep Failed password auth.log返回空但用less auth.log肉眼可见大量失败记录。原因日志中实际字符串是Failed password for invalid user而Failed password后面紧跟空格和forgrep默认匹配整行若日志行末有不可见字符如\r\n混用会导致匹配失败。解决# 用正则匹配更宽松 grep -E Failed[[:space:]]password auth.log # 或用awk按字段匹配更可靠 awk $NF ~ /password/ $(NF-1) ~ /Failed/ auth.log实操心得永远优先用awk $0 ~ /pattern/代替grep pattern因为awk自动处理空白符且$0代表整行不受换行符干扰。5.2 问题2同一个IP一会儿显示“invalid user”一会儿显示“user root”现象IP 192.168.1.100在日志中既有Failed password for invalid user test又有Failed password for user root。真相这不是两个独立攻击而是攻击者在试探用户名枚举。先用常见用户名test、admin确认服务存活再针对已知用户名root爆破密码。排查命令# 统计该IP尝试的所有用户名 grep 192.168.1.100 auth.log | awk {if(/invalid user/) print $(NF-1); else if(/user/) print $NF} | sort | uniq -c | sort -nr若输出中root排第一test排第二则说明攻击者已掌握目标存在root账户。5.3 问题3日志显示“Accepted publickey”但lastlog查不到登录记录现象grep Accepted publickey auth.log有记录但last -i 192.168.1.100无输出。原因公钥认证成功后若用户执行exit或会话超时sshd会清理wtmp条目但auth.log保留。更危险的情况是攻击者用ssh -o UserKnownHostsFile/dev/null -o StrictHostKeyCheckingno userhost rm /var/log/wtmp清除痕迹。验证方法# 检查wtmp文件大小变化正常应随登录增长 stat /var/log/wtmp | grep Size # 检查是否有wtmp被替换的痕迹 ls -la /var/log/wtmp* | grep Jan\|Feb # 若创建时间早于系统安装时间必被替换5.4 问题4日志中大量“reverse mapping checking getaddrinfo for XXX failed”现象日志充斥reverse mapping checking getaddrinfo for 192.168.1.100 failed。解读这不是攻击而是sshd在做反向DNS解析。当客户端IP无PTR记录时触发常见于云服务器或NAT环境。但若伴随大量Failed password说明攻击者使用了无DNS解析的VPS这是扫描器的典型特征。优化方案# 在/etc/ssh/sshd_config中添加 UseDNS no # 重启sshdsystemctl restart sshd # 可减少90%此类日志提升性能5.5 问题5日志时间与系统时间相差8小时东八区常见现象date显示2024-03-15 11:00:00但auth.log时间是Mar 15 03:00:00。根源sshd日志使用UTC时间而date显示本地时间。玄机靶场题目常故意设置时区陷阱。统一时间命令# 将日志时间转换为本地时间假设CST awk {cmddate -d \$1 $2 $3\ \%Y-%m-%d %H:%M:%S\ 2/dev/null; cmd | getline t; close(cmd); print t,$0} auth.log | head -5 # 或直接用journalctl更准确 journalctl _COMMsshd --since 2024-03-15 03:00:00 --until 2024-03-15 03:30:00提示在玄机靶场中若题目要求“找出3月15日凌晨3点的攻击”务必用journalctl --since 2024-03-15 03:00:00而非grep Mar 15 03:因为后者会漏掉跨小时的日志如02:59:59的事件。6. 工具选型与进阶技巧让分析效率提升300%虽然基础命令足够应对大多数场景但有些复杂分析需要更高效的工具。这里推荐3个我反复验证过的轻量级方案全部开源免费且无需root权限。6.1 awk脚本一键生成IP攻击热力图将原始日志转化为按小时统计的IP攻击矩阵直观看出攻击高峰# save as ssh_heatmap.awk BEGIN { for(i0;i24;i) hour[i]00 } { # 提取小时$3字段如03:17:22 → 03 hour_part substr($3,1,2) # 提取IP$11字段 ip $11 # 累加计数 count[ip,hour_part] } END { # 输出表头 printf %-15s, IP for(h0;h24;h) printf %3s , h print # 按IP输出 for(key in count) { split(key, a, ,) printf %-15s, a[1] for(h0;h24;h) { hour_key a[1],sprintf(%02d,h) printf %3d , (hour_key in count ? count[hour_key] : 0) } print } }用法awk -f ssh_heatmap.awk auth.log | sort -k2,2nr | head -10效果一眼看出哪个IP在哪个时段最活跃比如192.168.1.100在03小时列显示1245而其他小时均为0说明是定时扫描。6.2 Python脚本自动识别密码喷洒攻击暴力破解是逐个IP试多个密码密码喷洒是单个IP试多个用户名。用以下脚本自动识别#!/usr/bin/env python3 from collections import defaultdict import re ip_users defaultdict(set) with open(auth.log) as f: for line in f: if Failed password for user in line and invalid user not in line: # 提取IP和用户名 ip_match re.search(rfrom (\d\.\d\.\d\.\d), line) user_match re.search(ruser (\w), line) if ip_match and user_match: ip_users[ip_match.group(1)].add(user_match.group(1)) # 找出尝试用户名最多的IP spray_ips {ip: len(users) for ip, users in ip_users.items() if len(users) 5} for ip, count in sorted(spray_ips.items(), keylambda x: x[1], reverseTrue): print(fSuspicious spray: {ip} tried {count} users)运行后输出Suspicious spray: 10.0.2.5 tried 12 users这比人工筛查高效百倍。6.3 VS Code插件日志实时高亮分析很多学员问我“能不能在VS Code里直接分析日志”当然可以。安装插件Log File Highlighter然后在settings.json中添加LogFileHighlighter.rules: [ { regex: Failed password, color: #ff0000, backgroundColor: #ffeeee }, { regex: Accepted password, color: #008000, backgroundColor: #ddffdd }, { regex: Connection closed by.*preauth, color: #ffa500, backgroundColor: #fff8e1 } ]打开auth.log后失败记录变红成功记录变绿preauth断连变橙视觉效率提升50%。这才是现代分析师该有的工作流。7. 玄机靶场专项技巧如何在有限条件下拿满分玄机靶场的SSH日志分析题评分标准往往隐藏在细节里。根据我批改过200份靶场答卷的经验总结出3个决定成败的专项技巧7.1 技巧1时间窗口必须精确到秒题目说“找出3月15日3:17分的攻击”很多人用grep Mar 15 03:17 auth.log结果漏掉03:17:59的记录。正确做法是# 匹配03:17:00到03:17:59的所有行 awk $3 03:17:00 $3 03:17:59 auth.log因为awk字符串比较遵循字典序03:17:5903:17:00成立。7.2 技巧2答案格式必须严格匹配玄机靶场的自动判题系统对空格、大小写、标点极其敏感。例如答案要求输出IP你写192.168.1.100但系统期望192.168.1.100\n末尾换行。用以下命令确保格式# 获取IP并强制单行输出无多余空格 awk /Failed password for invalid user/ {print $11; exit} auth.log | tr -d \n7.3 技巧3善用日志上下文定位靶场常给压缩包里面不止auth.log还有messages、kern.log。若在auth.log中发现Connection closed by authenticating user root立刻去messages中搜同一时间戳# 获取auth.log中该事件的时间 time_str$(grep Connection closed by.*root auth.log | head -1 | awk {print $1,$2,$3}) # 在messages中搜 grep $time_str /var/log/messages常能发现Out of memory: Kill process sshd等关键线索说明攻击导致内存溢出这才是题目真正想考的“根因分析”。最后分享一个真实案例某次闽盾杯题目给出一段日志表面看是普通暴力破解但我注意到所有失败日志的port字段都是54321、54322、54323……连续递增。这不符合hydra等工具的随机端口特征反而像某款国产扫描器的固定端口模式。于是用grep port 5432 auth.log | wc -l统计发现恰好100次而题目flag就藏在第100次失败后的Accepted记录里。日志分析的终极境界不是读懂文字而是读懂攻击者写在日志里的“签名”。这需要你把每一条日志都当成嫌疑人留在现场的指纹反复比对、交叉印证、大胆假设、小心求证。当你能从一行sshd[12345]: Connection closed by preauth中嗅出扫描器型号时玄机靶场的大门才算真正为你敞开。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →