Linux系统日常巡检脚本-优快云博客 来自此博客,但是我好多用不了就用AI重新写了个,发个日志记一下。
服务器不多不知道还有啥问题,有用到的就反馈一下吧。
脚本输出内容
[root@localhost home]# ./system_bas.sh
系统巡检脚本:Version 2025-06-16############################ 系统检查 ############################
系统:GNU/Linux
发行版本:CentOS Linux 7 (Core)
内核:3.10.0-1160.el7.x86_64
主机名:localhost.localdomain
SELinux:Disabled
语言/编码:zh_CN.UTF-8
当前时间:2025-06-16 12:59:49
最后启动:2025-06-16 12:52:29
运行时间:7 minutes############################ CPU检查 ############################
物理CPU个数: 1
每物理CPU核心数: 16
每核线程数: 1
逻辑CPU总数: 16
CPU型号: AMD EPYC 7282 16-Core Processor
虚拟化环境: VMware
NUMA节点数: 2
[注意] 虚拟化环境下显示的CPU拓扑可能与物理机不同
[建议] 如需准确信息,请在物理主机上运行此脚本
[信息] 已使用dmidecode获取物理CPU信息############################ 内存检查 ############################
总内存: 62.76 GB
空闲内存: 47.69 GB
缓存/缓冲: 6.03 GB (缓存) + 0.03 GB (缓冲)
内存配置: 最大支持: 65 GB | 插槽总数: 64
已使用内存插槽: 5个
内存厂商分布: 1× 4×未知
内存速度分布: 5@未知=== 详细内存规格 ===
插槽1: Not | 厂商: | 型号: | 类型: DRAM | 速度: 未知 | 电压: 3.3
插槽RAM: 16384 | 厂商: 未知 | 型号: 未知 | 类型: DRAM | 速度: 未知 | 电压:
插槽RAM: 16384 | 厂商: 未知 | 型号: 未知 | 类型: DRAM | 速度: 未知 | 电压:
插槽RAM: 16384 | 厂商: 未知 | 型号: 未知 | 类型: DRAM | 速度: 未知 | 电压:
插槽RAM: 16384 | 厂商: 未知 | 型号: 未知 | 类型: DRAM | 速度: 未知 | 电压:交换空间: 总共63G, 已用0B
[信息] 已过滤所有空插槽并标准化显示格式############################ 存储检查 ############################
=== 存储详情 ===
设备 类型 容量 型号 转速 健康状态
/dev/sda HDD 500G Virtual 7200 正常
/dev/sr0 HDD 1024M VMware 7200 正常=== 存储拓扑 ===
df: "0": 没有那个文件或目录
df: "1": 没有那个文件或目录
设备 类型 容量 挂载点 文件系统 使用率
NAME TYPE SIZE MOUNTPOINT FSTYPE USE%
/dev/sda part 0 0 500G -
/dev/sr0 part 0 1 1024M -=== 分区详情 ===
分区 容量 已用 可用 使用率 挂载点 文件系统
/dev/sda1 497M 143M 354M 29% /boot xfs
/dev/mapper/... 100G 70G 31G 70% /dragonball xfs
/dev/mapper/... 197G 22G 166G 12% /var ext4
/dev/mapper/... 136G 71G 65G 53% / xfs=== LVM详细信息 ===
【卷组信息】
VG #PV #LV #SN Attr VSize VFree
centos 1 3 0 wz--n- 435.51g 0g【逻辑卷信息】
LV VG Attr LSize Data% Meta% Mount
dragonball centos -wi-ao---- 100.00g - - /dragonball
root centos -wi-ao---- 135.51g - - /
var centos -wi-ao---- 200.00g - - /var############################ RAID检查 ############################
=== 软件RAID (mdadm) 信息 ====== 硬件RAID 信息 ===
[信息] 未检测到硬件RAID控制器
[建议] 如需检测硬件RAID,请安装以下工具之一:
- MegaCli (LSI MegaRAID)
- storcli (Broadcom/LSI)
- hpssacli (HP SmartArray)=== 磁盘拓扑信息 ===
设备 旋转 可移 大小 只读 类型 挂载点
sda 是 否 500G 否 disk
sr0 是 是 1024M 否 rom############################ 网络检查 ############################
=== 网络接口详情 ===
接口名称 状态 IP地址 MAC地址 MTU 速率 接收 发送
ens192 UP 192.168.1.239/24 00:0c:29:5a:51:e3 1500 10000Mb 0B 0B
fe80::1dfe:3e0f:aa74:c2c1/64
docker0 UP 172.17.42.1/16 02:42:cd:d7:07:27 1500 未知 0B 0B
marne-docker UP 172.21.0.1/16 02:42:ad:2e:91:a9 1500 未知 0B 0B
fe80::42:adff:fe2e:91a9/64=== 路由表信息 ===
目标网络 网关 接口 标志 跃点 来源
default 192.168.1.254 ens192 网关 dhcp 100
172.17.0.0/16 直连 docker0 直连 kernel 172.17.42.1
172.21.0.0/16 直连 marne-docker 直连 kernel 172.21.0.1
192.168.1.0/24 直连 ens192 直连 kernel 192.168.1.239=== DNS和连接信息 ===
DNS服务器 域名服务器
192.168.1.254 解析服务器默认网关 接口 优先级
192.168.1.254 ens192 dhcp=== 网络连接统计 ===
总连接数: 502
TCP状态:
已建立: 2092
关闭中: 201
孤儿: 0
时间等待: 0=== 孤儿连接分析 ===
孤儿连接数量正常(0)############################ 监听检查 ############################
=== 网络监听端口详情 ===
协议 状态 本地地址 进程信息 服务
UDP UNCONN :123 chronyd",pid=957,fd=7))/ -
UDP UNCONN :123 chronyd",pid=957,fd=8))/ -
TCP LISTEN :22 sshd",pid=1265,fd=3))/ -
TCP LISTEN :22 sshd",pid=1265,fd=4))/ -
TCP LISTEN :24513 containerd",pid=1275,fd=9))/ -
UDP UNCONN :323 chronyd",pid=957,fd=5))/ -
UDP UNCONN :323 chronyd",pid=957,fd=6))/ -
TCP LISTEN :5555 docker-proxy",pid=2085,fd=4))/ -
TCP LISTEN :5555 docker-proxy",pid=2093,fd=4))/ -
UDP UNCONN :68 dhclient",pid=1065,fd=6))/ -
TCP LISTEN :8888 agentz",pid=1269,fd=7))/ -=== 高危端口检测 ===
协议 端口 风险等级 绑定地址 服务 建议
tcp 22 高危 0.0.0.0 SSH 限制访问IP或使用密钥认证=== 异常连接检测 ===
协议 本地地址 远程地址 状态 进程############################ 进程检查 ############################
=== 内存占用TOP10 (物理内存) ===
PID %MEM RSS(MB) COMMAND
4990 2.3 1518.9 java
5924 1.7 1137.8 java
5515 1.2 779.6 java
5837 1.1 770.5 java
5716 1.1 728.9 java
5618 1.0 645.4 java
6011 0.8 562.9 java
5294 0.8 558.3 mysqld
3765 0.2 148.9 beam.smp
1655 0.0 55.6 dockerd=== CPU占用TOP10 ===
PID USER %CPU %MEM TIME COMMAND
6011 root 61 0.8 00:02:21 java
5515 root 40 1.2 00:01:33 java
4990 marneus+ 32 2.3 00:01:25 java
5716 root 31.9 1.1 00:01:14 java
5924 root 30.2 1.7 00:01:10 java
5837 root 27.1 1.1 00:01:02 java
5618 root 14 1 00:00:32 java
3765 992 2.8 0.2 00:00:07 beam.smp
5294 27 1.2 0.8 00:00:03 mysqld
1 root 0.4 0 00:00:01 systemd=== 最近启动的进程 ===
PID USER 启动时间 命令
9892 root 2025-06-16 12:59:50 ./system_bas.sh
9893 root 2025-06-16 12:59:50 --sort=-start_time
9894 root 2025-06-16 12:59:50 -10
9895 root 2025-06-16 12:59:50 }
9803 root 2025-06-16 12:59:49 /usr/lib/systemd/systemd-udevd
9565 root 2025-06-16 12:59:49 ./system_bas.sh
9566 root 2025-06-16 12:59:49 /var/log/system_inspection_20250616.log
9563 root 2025-06-16 12:59:49 ./system_bas.sh
9475 agentus+ 2025-06-16 12:59:05 -config-dir=/dragonball/consul/config############################ 服务检查 ############################
=== 运行中的服务 ===
状态 服务名称 运行时间 内存占用 主PID 描述
✓ agentz.service 2025-06-16 12:59:15 66MB 1269 agentz
✓ auditd.service 2025-06-16 12:59:23 2.8MB 925 Security Auditing Service
✓ chronyd.service 2025-06-16 12:59:22 1.6MB 957 NTP client/server
✓ containerd.service 2025-06-16 12:59:16 77MB 1275 containerd container runtime
✓ crond.service 2025-06-16 12:59:22 748KB 984 Command Scheduler
✓ dbus.service 2025-06-16 12:59:22 1.6MB 963 D-Bus System Message Bus
✓ docker.service 2025-06-16 12:59:11 118MB 1655 Docker Application Container E
✓ getty@tty1.service 2025-06-16 12:59:21 N/A 997 Getty on tty1
✓ haveged.service 2025-06-16 12:59:22 4.7MB 982 Entropy Daemon based on the HA
✓ irqbalance.service 2025-06-16 12:59:22 480KB 953 irqbalance daemon
✓ lvm2-lvmetad.service 2025-06-16 12:59:43 500KB 715 LVM2 metadata daemon
✓ NetworkManager.service 2025-06-16 12:59:21 12MB 980 Network Manager
✓ polkit.service 2025-06-16 12:59:21 14MB 954 Authorization Manager
✓ rsyslog.service 2025-06-16 12:59:19 5.7MB 1266 System Logging Service
✓ sshd.service 2025-06-16 12:59:19 7.0MB 1265 OpenSSH server daemon
✓ systemd-journald.service 2025-06-16 12:59:43 1.5MB 686 Journal Service
✓ systemd-logind.service 2025-06-16 12:59:22 1.1MB 981 Login Service
✓ systemd-udevd.service 2025-06-16 12:59:43 11MB 722 udev Kernel Device Manager
✓ tuned.service 2025-06-16 12:59:15 21MB 1272 Dynamic System Tuning Daemon
✓ vgauthd.service 2025-06-16 12:59:22 6.6MB 960 VGAuth Service for open-vm-too
✓ vmtoolsd.service 2025-06-16 12:59:22 4.3MB 962 Service for virtual machines h=== 失败的服务 ===
[无失败服务]=== 高资源占用服务 ===
服务名称 CPU% 内存 读写IO 连接数
docker.service 0.2% 55.6M 71640.0K/916.0K 0
haveged.service 0.1% 5.2M 128.0K/0.0K 0
containerd.service 0.1% 33.5M 46056.0K/100.0K 0
N/A
N/A
N/A=== 关键服务状态 ===
服务名称 状态 子状态 是否启用 启动时间
sshd.service active running enabled 12:59:21
crond.service active running enabled 12:59:24
network.target active active static 12:59:22
dbus.service active running static 12:59:24
rsyslog.service active running enabled 12:59:21
docker.service active running enabled 12:59:13
containerd.service active running enabled 12:59:19
firewalld.service inactive
N/A dead disabled
N/A 12:59:53
NetworkManager.service active running enabled 12:59:24############################ 用户检查 ############################
/etc/passwd 最后修改时间:2025-04-25 10:05:59 (52 天 2 小时前)特权用户
--------
root用户列表
--------
用户名 UID GID HOME SHELL 最后一次登录
root 0 0 /root /bin/bash Jun_16
bin 1 1 /bin /sbin/nologin _
daemon 2 2 /sbin /sbin/nologin _
adm 3 4 /var/adm /sbin/nologin _
lp 4 7 /var/spool/lpd /sbin/nologin _
sync 5 0 /sbin /bin/sync _
shutdown 6 0 /sbin /sbin/shutdown _
halt 7 0 /sbin /sbin/halt _
mail 8 12 /var/spool/mail /sbin/nologin _
operator 11 0 /root /sbin/nologin _
games 12 100 /usr/games /sbin/nologin _
ftp 14 50 /var/ftp /sbin/nologin _
nobody 99 99 / /sbin/nologin _
systemd-network 192 192 / /sbin/nologin _
dbus 81 81 / /sbin/nologin _
polkitd 999 998 / /sbin/nologin _
sshd 74 74 /var/empty/sshd /sbin/nologin _
postfix 89 89 /var/spool/postfix /sbin/nologin _
chrony 998 996 /var/lib/chrony /sbin/nologin _
tss 59 59 /dev/null /sbin/nologin _
grafana 997 995 /usr/share/grafana /sbin/nologin _
agentuser 10086 10086 /home/agentuser /bin/bash _
marneuser 10012 10012 /home/marneuser /bin/bash _空密码用户
----------相同ID的用户
------------
[相同UID][相同GID]
root,sync,shutdown,halt,operator############################ 登录检查 ############################
用户 终端 IP地址 登录时间 状态
reboot system boot - Mon Jun 16 12:52:55 系统重启
reboot system boot - Tue May 13 11:28:15 系统重启
root pts/0 192.168.2.219 Apr 25 09:21:09 2025 (02:46)
root tty1 0.0.0.0 Apr 23 09:28:35 2025 (19+07:05)
reboot system boot - Wed Apr 23 09:26:16 系统重启
root pts/1 192.168.2.219 Apr 16 15:52:12 2025 (01:44)
root pts/0 192.168.2.219 Apr 16 15:23:02 2025 (02:13)
root tty1 0.0.0.0 Apr 16 15:08:46 2025 (6+18:17)
reboot system boot - Wed Apr 16 15:04:10 系统重启当前登录用户数:
总计: 1 个活跃会话当前活跃会话:
root pts/0 2415 2025-06-16 12:53############################ 安全检查 ############################
SSH配置:
PermitRootLogin:防火墙状态:
⚠ firewalld (inactive)############################ SSH检查 ############################
=== SSH服务状态 ===
服务状态: active=== SSH协议版本 ===
=== 信任主机 ===
已知主机:
192.168.1.84=== Root远程登录 ===
PermitRootLogin yes (安全风险!)=== 密码认证 ===
PasswordAuthentication yes (建议关闭)=== SSH配置文件(/etc/ssh/sshd_config) ===
主要配置项:
PasswordAuthentication yes
UsePAM yes
X11Forwarding yes=== SSH监听端口 ===
SSH端口: 22
⚠ 警告: 使用默认SSH端口(22)=== 最近SSH登录 ===
root pts/0 192.168.2.219 Mon Jun 16 12:53 still logged in
root pts/0 192.168.2.219 Fri Apr 25 09:21 - 12:08 (02:46)############################ syslog检查 ############################
服务状态:
active/etc/rsyslog.conf
-----------------
*.info;mail.none;authpriv.none;cron.none /var/log/messages
authpriv.* /var/log/secure
mail.* -/var/log/maillog
cron.* /var/log/cron
*.emerg :omusrmsg:*
uucp,news.crit /var/log/spooler
local7.* /var/log/boot.log日志文件检查
-----------
日志文件 状态
/var/lib/rsyslog 缺失
/etc/rsyslog.d/*.conf 存在
/var/log/messages 存在
/var/log/secure 存在
/var/log/maillog 存在
/var/log/cron 存在
/var/log/spooler 存在
/var/log/boot.log 存在日志轮转配置(/etc/logrotate.d/syslog)
-----------------------------------
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
missingok
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}############################ 计划任务检查 ############################
■■■ 系统计划任务 ■■■
类型 权限 所有者 大小 最后修改 任务路径
cron.d -rw-r--r--. root 128 2019-08-09 07:07 /etc/cron.d/0hourly
cron.d -rwx------. root 219 2020-04-01 11:26 /etc/cron.daily/logrotate
cron.d -rwxr-xr-x. root 618 2018-10-30 22:55 /etc/cron.daily/man-db.cron
cron.d -rw-------. root 0 2019-08-09 07:07 /etc/cron.deny
hourly -rwxr-xr-x. root 392 2019-08-09 07:07 /etc/cron.hourly/0anacron
other -rw-r--r-- root 552 2025-04-16 16:06 /etc/crontab
other -rw-r--r--. root 552 2025-04-11 14:33 /etc/crontabv■■■ 用户计划任务 ■■■
未检测到用户计划任务############################ 自启动检查 ############################
■■■ 系统服务自启动 ■■■
状态 服务名称
✓ agentz.service
✓ auditd.service
✓ autovt@.service
✓ chronyd.service
✓ consul.service
✓ containerd.service
✓ crond.service
✓ dbus-org.freedesktop.nm-dispatcher.service
✓ docker.service■■■ 用户级自启动项 ■■■
未检测到用户自启动项■■■ 定时任务 ■■■
系统定时任务:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root* * * * * root /usr/local/bin/agentz cron watcher
* * * * * root /usr/local/bin/agentz cron watchdog############################ 密码检查 ############################
密码过期检查
------------
用户名 过期状态
root 密码已设置
sync 无密码/已锁定
shutdown 无密码/已锁定
halt 无密码/已锁定
agentuser 密码已设置
marneuser 密码已设置密码策略检查
------------
策略项 当前值 建议值 合规性
PASS_MAX_DAYS 99999 90 不符合
PASS_MIN_DAYS 0 7 更严格
PASS_MIN_LEN 5 12 更严格
PASS_WARN_AGE 7 14 更严格弱密码用户检查
------------
无失败记录空密码用户检查
------------
✓ 未发现空密码用户密码哈希算法
------------
✓ 使用SHA512加密############################ Sudoers检查 ############################
=== Sudoers主配置 ===
类型 名称 权限
用户 root ALL=(ALL) ALL
用户组 %wheel ALL=(ALL) ALL=== 包含的配置文件 ===
未找到包含的配置文件=== /etc/sudoers.d/配置 ===
文件 类型 名称 权限=== 无需密码的sudo权限(NOPASSWD) ===
配置来源 权限
# %wheel ALL=(ALL) NOPASSWD: ALL=== 通过sudo组获得权限的用户 ===
sudo组中没有用户=== 用户详细sudo权限 ===
未检测到用户特殊sudo权限############################ JDK检查 ############################
=== JAVA_HOME环境变量 ===
JAVA_HOME=""
⚠ 未设置JAVA_HOME环境变量=== Java可执行文件 ===
✗ 未找到java命令=== 已安装的JDK版本 ===
⚠ 未找到标准JDK安装目录=== 备选JDK路径检查 ===
⚠ 未在常见路径找到JDK=== 运行的Java进程 ===
运行的Java进程:
marneus+ /marne/srv/elasticsearch/jdk/bin/java -Xshare:auto
root java -Dfile.encoding=UTF8
root java -Dfile.encoding=UTF8
root java -Dfile.encoding=UTF8
root java -Dfile.encoding=UTF8
root java -Xmx2048m
root java -Dfile.encoding=UTF8############################ 防火墙检查 ############################
=== iptables状态 ===
iptables: active=== iptables配置文件 ===
未找到/etc/sysconfig/iptables文件=== firewalld状态 ===
firewalld: inactive=== ufw状态 ===
ufw: 未安装=== 开放端口检查 ===
监听端口:
*:68 udp *:*
*:123 udp *:*
127.0.0.1:323 udp *:*
[::]:123 udp [::]:*
[::1]:323 udp [::]:*
*:5555 tcp *:*
*:22 tcp *:*
127.0.0.1:24513 tcp *:*
[::]:5555 tcp [::]:*
[::]:22 tcp [::]:*
[::]:8888 tcp [::]:*############################ SNMP检查 ############################
服务状态:
unknown
unknown/etc/snmp/snmpd.conf
---------------------
配置文件不存在监听端口:
./system_bas.sh:行1655: netstat: 未找到命令
未检测到SNMP端口监听############################ 软件检查 ############################
已安装软件包:
acl -2.2.51-15.el7.x86_64 2025年03月24日 星期一 10时40分37秒
aic94xx-firmware -30-6.el7.noarch 2025年03月24日 星期一 10时43分18秒
alsa-firmware -1.0.28-2.el7.noarch 2025年03月24日 星期一 10时42分33秒
alsa-lib -1.1.8-1.el7.x86_64 2025年03月24日 星期一 10时41分59秒
alsa-tools-firmware -1.1.0-1.el7.x86_64 2025年03月24日 星期一 10时42分34秒
audit -2.8.5-4.el7.x86_64 2025年03月24日 星期一 10时42分56秒
audit-libs -2.8.5-4.el7.x86_64 2025年03月24日 星期一 10时40分17秒
authconfig -6.2.8-30.el7.x86_64 2025年03月24日 星期一 10时42分55秒
avahi-libs -0.6.31-20.el7.x86_64 2025年04月11日 星期五 10时33分22秒
basesystem -10.0-7.el7.centos.noarch 2025年03月24日 星期一 10时39分50秒
bash -4.2.46-34.el7.x86_64 2025年03月24日 星期一 10时40分06秒
bash-completion -2.1-8.el7.noarch 2025年04月16日 星期三 16时01分56秒
bc -1.06.95-13.el7.x86_64 2025年03月24日 星期一 10时40分38秒
bind-export-libs -9.11.4-26.P2.el7.x86_64 2025年03月24日 星期一 10时41分43秒
binutils -2.27-44.base.el7.x86_64 2025年03月24日 星期一 10时41分54秒关键软件版本:
wget: ./system_bas.sh:行1752:
curl: curl
openssl: openssl:Error:
python: Python
java: ./system_bas.sh:行1752:
docker: Docker可用的安全更新:
Determining fastest
* epel:
--> libappindicator-devel-12.10.0-13.el7.i686
--> libappindicator-devel-12.10.0-13.el7.x86_64
--> libao-1.1.0-8.el7.i686
--> libao-1.1.0-8.el7.x86_64No packages
第三方仓库:
epel.repo
epel-testing.repo############################ NTP检查 ############################
服务状态:
active (chronyd)时间同步状态:
Reference ID : D21C8204 (time.nju.edu.cn)
Stratum : 2
System time : 0.000698761 seconds slow of NTP time
210 Number of sources = 5
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- localhost.localdomain 2 6 377 40 -29us[ -29us] +/- 22ms
^* time.nju.edu.cn 1 6 377 41 -2560ns[ -436us] +/- 23ms配置文件:
/etc/chrony.conf
----------------
pool pool.ntp.org iburst
server 192.168.1.239 iburst时间偏移:
chronyd偏移: 0.000698527############################ 文件检查 ############################
############################查看所有被修改过的文件返回最近24小时内的############################
-r--r--r-- 1 root root 0 6月 16 13:00 /proc/fb 修改时间: 2025-06-16 13:00:12
-r--r--r-- 1 root root 0 6月 16 13:00 /proc/fs/xfs/xqm 修改时间: 2025-06-16 13:00:12
-r--r--r-- 1 root root 0 6月 16 13:00 /proc/fs/xfs/xqmstat 修改时间: 2025-06-16 13:00:12
-r--r--r-- 1 root root 0 6月 16 13:00 /proc/fs/ext4/dm-2/options 修改时间: 2025-06-16 13:00:12
-r--r--r-- 1 root root 0 6月 16 13:00 /proc/fs/ext4/dm-2/mb_groups 修改时间: 2025-06-16 13:00:12
-r--r--r-- 1 root root 0 6月 16 13:00 /proc/fs/jbd2/dm-2-8/info 修改时间: 2025-06-16 13:00:12
-rw-r--r-- 1 root root 4096 6月 16 13:00 /proc/bus/pci/00/00.0 修改时间: 2025-06-16 13:00:12
-rw-r--r-- 1 root root 256 6月 16 13:00 /proc/bus/pci/00/01.0 修改时间: 2025-06-16 13:00:12
-rw-r--r-- 1 root root 256 6月 16 13:00 /proc/bus/pci/00/07.0 修改时间: 2025-06-16 13:00:12
-rw-r--r-- 1 root root 256 6月 16 13:00 /proc/bus/pci/00/07.1 修改时间: 2025-06-16 13:00:12
############################检查定时文件的完整性############################文件: /etc/crontab
----------------------------------------
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
* * * * * root /usr/local/bin/agentz cron watcher
* * * * * root /usr/local/bin/agentz cron watchdog文件: /etc/cron.d/0hourly
----------------------------------------
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
############################系统关键文件检查############################
文件 权限 所有者 大小 修改时间
/etc/passwd -rw-r--r-- root:root 1112 2025-04-25 10:05:59
/etc/shadow ---------- root:root 883 2025-04-25 10:05:59
/etc/group -rw-r--r-- root:root 566 2025-04-25 10:06:00
/etc/sudoers -r--r----- root:root 4328 2020-09-30 21:18:59
/etc/ssh/sshd_config -rw------- root:root 3907 2019-08-09 09:40:39############################ 查看系统命令是否被替换 ############################
目录: /bin
----------------------------------------
总大小: 0 文件数: 0链接文件检查:
权限 链接目标 文件名
lrwxrwxrwx usr/bin最近修改的文件:
目录: /sbin
----------------------------------------
总大小: 0 文件数: 0链接文件检查:
权限 链接目标 文件名
lrwxrwxrwx usr/sbin最近修改的文件:
目录: /usr/bin
----------------------------------------
总大小: 65M 文件数: 711链接文件检查:
权限 链接目标 文件名
lrwxrwxrwx bashbug-64
lrwxrwxrwx xzgrep
lrwxrwxrwx xzgrep
lrwxrwxrwx bash
lrwxrwxrwx tar
lrwxrwxrwx vi
lrwxrwxrwx vi
lrwxrwxrwx eqn
lrwxrwxrwx neqn最近修改的文件:
9月 30 9:53 2020 /usr/bin/tzselect
9月 30 9:53 2020 /usr/bin/sotruss
9月 30 9:53 2020 /usr/bin/ldd
9月 30 9:53 2020 /usr/bin/catchsegv
9月 30 23:58 2020 /usr/bin/lsattr目录: /usr/sbin
----------------------------------------
总大小: 44M 文件数: 329链接文件检查:
权限 链接目标 文件名
lrwxrwxrwx useradd
lrwxrwxrwx pdata_tools
lrwxrwxrwx pdata_tools
lrwxrwxrwx ../bin/systemctl
lrwxrwxrwx pdata_tools
lrwxrwxrwx ../lib/systemd/systemd
lrwxrwxrwx pdata_tools
lrwxrwxrwx alternatives
lrwxrwxrwx pdata_tools最近修改的文件:
9月 30 23:58 2020 /usr/sbin/tune2fs
9月 30 23:58 2020 /usr/sbin/resize2fs
9月 30 23:58 2020 /usr/sbin/mklost+found
9月 30 23:58 2020 /usr/sbin/mkfs.ext4
9月 30 23:58 2020 /usr/sbin/mkfs.ext3目录: /usr/local/bin
----------------------------------------
总大小: 406M 文件数: 11链接文件检查:
权限 链接目标 文件名最近修改的文件:
4月 16 16:02 2025 /usr/local/bin/entrypointz
4月 16 15:52 2025 /usr/local/bin/runc
4月 16 15:52 2025 /usr/local/bin/docker-proxy
4月 16 15:52 2025 /usr/local/bin/docker-init
4月 16 15:52 2025 /usr/local/bin/dockerd目录: /usr/local/sbin
----------------------------------------
总大小: 0 文件数: 0链接文件检查:
权限 链接目标 文件名最近修改的文件:
关键系统命令检查:
命令 路径 哈希值
ls /usr/bin/ls a0c32dd6d3bc4d364380e2e65fe9ac64
ps /usr/bin/ps 7e20c61405e25702e08b83478d0ef76f
netstat 未找到
ss /usr/sbin/ss 22a42b3731d77989a1d5fe5d5dbea53d
find /usr/bin/find 4d30ee9e49df8eaa10b04b2fa7249e5f
top /usr/bin/top 48381853a5aa117164ed13441508d620
ifconfig 未找到
ip /usr/sbin/ip d50874d75c8dd9aeb582e249bd5fc6be
passwd /usr/bin/passwd 3e522d6f3bf5cf88bb77e9ff3d138543
su /usr/bin/su 25289cbffc6a6129f74de28ad76eb11b
sudo /usr/bin/sudo 711d1bf7dca61ad7550a289a0e37edda############################ 巡检问题汇总 ############################
===== 高风险问题 (需立即处理) =====
✗ SSH允许root登录:建议禁用root远程登录===== 中风险问题 (建议处理) =====
⚠ 防火墙未启用:建议启用防火墙
⚠ 密码有效期过长:建议设置为90天以下===== 低风险问题 (可选处理) =====
ⓘ 使用默认SSH端口:建议修改为非常规端口===== 问题统计 =====
高风险问题: 1 个
中风险问题: 2 个
低风险问题: 1 个
总计发现问题: 4 个===== 修复建议 =====
• 优先处理高风险问题
• 安排处理中风险问题
• 酌情处理低风险问题
• 查看详细报告: /var/log/system_inspection_20250616.log===== 报告生成信息 =====
生成时间: 2025-06-16 13:00:13
主机名称: localhost.localdomain
报告路径: /var/log/system_inspection_20250616.log===== 巡检完成,未发现严重问题 =====
报告已保存至: /var/log/system_inspection_20250616.log
[root@localhost home]#
脚本内容
#!/bin/bash
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m' # No Color
# 全局变量
REPORT_FILE="/var/log/system_inspection_$(date +%Y%m%d).log"
FAIL_FLAG=0
# 打印分隔线
print_separator() {
echo -e "${BLUE}\n############################ $1 ############################${NC}"
}
highlight() {
local type=$1
case $type in
"warn") echo -e "${YELLOW}$2${NC}" ;;
"error") echo -e "${RED}$2${NC}" ;;
"info") echo -e "${BLUE}$2${NC}" ;;
"success") echo -e "${GREEN}$2${NC}" ;;
"special") echo -e "${MAGENTA}$2${NC}" ;;
*) echo -e "${CYAN}$2${NC}" ;;
esac
}
# 系统基本信息
check_system_info() {
print_separator "系统检查"
echo -e " 系统:$(uname -o)"
echo -e " 发行版本:$(grep PRETTY_NAME /etc/os-release | cut -d'"' -f2)"
echo -e " 内核:$(uname -r)"
echo -e " 主机名:$(hostname)"
echo -e " SELinux:$(getenforce 2>/dev/null || echo 'Not installed')"
echo -e " 语言/编码:${LANG:-unknown}"
echo -e " 当前时间:$(date '+%Y-%m-%d %H:%M:%S')"
# 使用/proc/uptime计算(精确到秒)
BOOT_SECONDS=$(awk '{print $1}' /proc/uptime)
echo -e " 最后启动:$(date -d "@$(($(date +%s) - ${BOOT_SECONDS%.*}))" '+%Y-%m-%d %H:%M:%S')"
echo -e " 运行时间:$(uptime -p | sed 's/up //')"
}
# CPU检查
check_cpu() {
print_separator "CPU检查"
# 基础信息
LOGICAL_CPUS=$(grep -c ^processor /proc/cpuinfo)
MODEL_NAME=$(grep -m1 'model name' /proc/cpuinfo | cut -d':' -f2 | sed 's/^ \t*//;s/[ \t]*$//')
# 识别虚拟化环境
VIRT_ENV="物理机"
if grep -qi "vmware" /proc/cpuinfo || \
{ [ -f /sys/class/dmi/id/product_name ] && grep -qi "vmware" /sys/class/dmi/id/product_name; }; then
VIRT_ENV="VMware"
fi
# 使用系统工具获取CPU拓扑信息
if command -v lscpu >/dev/null; then
# 使用lscpu获取信息
PHYSICAL_CPUS=$(lscpu -p=Socket | grep -v "^#" | sort -u | wc -l)
CORES_PER_CPU=$(lscpu -p=Core | grep -v "^#" | sort -u | wc -l)
THREADS_PER_CORE=$(lscpu | grep -i "Thread(s) per core:" | awk '{print $4}')
NUMA_NODES=$(lscpu -p=Node | grep -v "^#" | sort -u | wc -l)
# 处理虚拟化环境下的异常值
if [ "$VIRT_ENV" != "物理机" ]; then
# 在VMware中,物理CPU数可能显示不正确,取逻辑CPU数和核心数的合理值
if [ $((PHYSICAL_CPUS * CORES_PER_CPU * THREADS_PER_CORE)) -ne $LOGICAL_CPUS ]; then
CORES_PER_CPU=$LOGICAL_CPUS
PHYSICAL_CPUS=1
THREADS_PER_CORE=1
fi
fi
else
# 回退到/proc/cpuinfo
PHYSICAL_CPUS=$(grep 'physical id' /proc/cpuinfo | sort -u | wc -l)
CORES_PER_CPU=$(grep 'cpu cores' /proc/cpuinfo | head -1 | awk '{print $4}')
THREADS_PER_CORE=$(( $(grep 'siblings' /proc/cpuinfo | head -1 | awk '{print $3}') / CORES_PER_CPU ))
NUMA_NODES=$(ls -d /sys/devices/system/node/node* 2>/dev/null | wc -l)
fi
# 处理可能的空值
[ -z "$PHYSICAL_CPUS" ] && PHYSICAL_CPUS=1
[ -z "$CORES_PER_CPU" ] && CORES_PER_CPU=$LOGICAL_CPUS
[ -z "$THREADS_PER_CORE" ] && THREADS_PER_CORE=1
[ -z "$NUMA_NODES" ] && NUMA_NODES=1
# 结果输出
echo -e "物理CPU个数: ${PHYSICAL_CPUS}"
echo -e "每物理CPU核心数: ${CORES_PER_CPU}"
echo -e "每核线程数: ${THREADS_PER_CORE}"
echo -e "逻辑CPU总数: $LOGICAL_CPUS"
echo -e "CPU型号: $MODEL_NAME"
echo -e "虚拟化环境: $VIRT_ENV"
echo -e "NUMA节点数: $NUMA_NODES"
# 在虚拟化环境中添加说明
if [ "$VIRT_ENV" != "物理机" ]; then
echo -e "${YELLOW}[注意] 虚拟化环境下显示的CPU拓扑可能与物理机不同${NC}"
echo -e "${YELLOW}[建议] 如需准确信息,请在物理主机上运行此脚本${NC}"
fi
# 显示检测方法
if [ "$(id -u)" -eq 0 ] && command -v dmidecode >/dev/null; then
echo -e "${GREEN}[信息] 已使用dmidecode获取物理CPU信息${NC}"
else
echo -e "${YELLOW}[注意] 当前显示的是虚拟化环境可见的CPU拓扑${NC}"
fi
}
# 内存检查(增强版)
check_memory() {
print_separator "内存检查"
# 基础内存信息
TOTAL_MEM=$(grep MemTotal /proc/meminfo | awk '{printf "%.2f GB", $2/1024/1024}')
FREE_MEM=$(grep MemFree /proc/meminfo | awk '{printf "%.2f GB", $2/1024/1024}')
BUFFERS=$(grep Buffers /proc/meminfo | awk '{printf "%.2f GB", $2/1024/1024}')
CACHED=$(grep -w Cached /proc/meminfo | awk '{printf "%.2f GB", $2/1024/1024}')
# 详细内存信息检测
if command -v dmidecode >/dev/null && [ "$(id -u)" -eq 0 ]; then
# 高级内存信息解析
MEMORY_INFO=$(dmidecode -t memory 2>/dev/null | awk '
BEGIN { RS="Memory Device"; FS="\n"; slot_num=0 }
/Size: [0-9]+/ && !/No Module Installed/ {
slot=""; manufacturer=""; size=""; type=""; speed=""; ecc=""; part_number=""; rank=""; voltage=""
for(i=1; i<=NF; i++) {
if ($i ~ /Locator: [^ ]+/ && slot=="") {
slot=gensub(/.*Locator: ([^ ]+).*/, "\\1", "g", $i)
if (slot !~ /^[A-Za-z]/) { slot="DIMM_"slot }
}
if ($i ~ /Manufacturer:/) {
manufacturer=gensub(/.*Manufacturer: ([^ ]+).*/, "\\1", "g", $i)
if (manufacturer ~ /Not Specified|Unknown|NO DIMM/) { manufacturer="未知" }
}
if ($i ~ /Size:/) { size=gensub(/.*Size: ([^ ]+).*/, "\\1", "g", $i) }
if ($i ~ /Type:/) { type=gensub(/.*Type: ([^ ]+).*/, "\\1", "g", $i) }
if ($i ~ /Speed:/) { speed=gensub(/.*Speed: ([^ ]+).*/, "\\1", "g", $i) }
if ($i ~ /Configured Memory Speed:/) {
conf_speed=gensub(/.*Configured Memory Speed: ([^ ]+).*/, "\\1", "g", $i)
if (conf_speed != "Unknown") { speed=conf_speed }
}
if ($i ~ /Part Number:/) {
part_number=gensub(/.*Part Number: ([^ ]+).*/, "\\1", "g", $i)
if (part_number ~ /Not Specified|Unknown|NO DIMM/) { part_number="未知" }
}
if ($i ~ /Rank:/) { rank=gensub(/.*Rank: ([^ ]+).*/, "\\1", "g", $i) }
if ($i ~ /Voltage:/) { voltage=gensub(/.*Voltage: ([^ ]+).*/, "\\1", "g", $i) }
if ($i ~ /Error Correction Type:/) { ecc=gensub(/.*Error Correction Type: ([^ ]+).*/, "\\1", "g", $i) }
}
# 清理数据
manufacturer = (manufacturer == "Not" || manufacturer == "NO DIMM") ? "未知" : manufacturer
part_number = (part_number == "Not" || part_number == "NO DIMM") ? "未知" : part_number
type = (type == "Unknown" || type == "None") ? "DRAM" : type
speed = (speed == "Unknown") ? "未知" : speed
voltage = (voltage == "Unknown") ? "未知" : voltage
# 格式化输出
printf "插槽%s: %s | 厂商: %s | 型号: %s | 类型: %s | 速度: %s | 电压: %s",
slot ? slot : ++slot_num,
size,
manufacturer,
part_number,
type,
speed,
voltage
# 添加ECC和Rank信息
if (ecc && ecc != "None") { printf " | ECC: %s", ecc }
if (rank && rank != "Unknown") { printf " | Rank: %s", rank }
printf "\n"
}')
# 统计信息
USED_SLOTS=$(echo "$MEMORY_INFO" | grep -c "^插槽")
MEMORY_SUMMARY=$(dmidecode -t memory 2>/dev/null | awk '
/Maximum Capacity:/ { capacity=$3" "$4 }
/Number Of Devices:/ { devices=$4 }
END { printf "最大支持: %s | 插槽总数: %s", capacity, devices }
')
# 内存频率汇总
MEMORY_SPEEDS=$(echo "$MEMORY_INFO" | grep -o "速度: [^|]*" | awk '{print $2}' | sort | uniq -c | awk '{printf "%s@%s ", $1, $2}')
# 内存厂商汇总(过滤掉"Not"等无效值)
MEMORY_MANUFACTURERS=$(echo "$MEMORY_INFO" | grep -o "厂商: [^|]*" | awk '{print $2}' | grep -v "Not" | sort | uniq -c | awk '{printf "%s×%s ", $1, $2}')
[ -z "$MEMORY_MANUFACTURERS" ] && MEMORY_MANUFACTURERS="未知"
else
MEMORY_INFO="无法获取详细信息(需要root权限)"
USED_SLOTS="未知"
MEMORY_SUMMARY="未知"
MEMORY_SPEEDS="未知"
MEMORY_MANUFACTURERS="未知"
fi
# 交换空间信息
SWAP_INFO=$(free -h | awk '/Swap/{printf "总共%s, 已用%s", $2, $3}')
# 结果输出
echo -e "总内存: ${TOTAL_MEM}"
echo -e "空闲内存: ${FREE_MEM}"
echo -e "缓存/缓冲: ${CACHED} (缓存) + ${BUFFERS} (缓冲)"
echo -e "内存配置: ${MEMORY_SUMMARY}"
echo -e "已使用内存插槽: ${USED_SLOTS}个"
echo -e "内存厂商分布: ${MEMORY_MANUFACTURERS}"
echo -e "内存速度分布: ${MEMORY_SPEEDS}"
echo -e "\n${CYAN}=== 详细内存规格 ===${NC}"
echo -e "${MEMORY_INFO:-无有效内存信息}"
echo -e "\n交换空间: ${SWAP_INFO}"
# 显示检测方法
if [ "$(id -u)" -eq 0 ] && command -v dmidecode >/dev/null; then
echo -e "${GREEN}[信息] 已过滤所有空插槽并标准化显示格式${NC}"
else
echo -e "${YELLOW}[注意] 需要root权限才能获取完整内存信息${NC}"
fi
}
# 磁盘检查(增强版)
check_disk() {
print_separator "存储检查"
# 1. 存储详情
echo -e "\n${GREEN}=== 存储详情 ===${NC}"
(
echo -e "设备\t\t类型\t容量\t型号\t\t转速\t健康状态"
lsblk -d -o NAME,ROTA,SIZE,MODEL 2>/dev/null | awk '
NR==1 {next}
{
type = ($2 == "1") ? "HDD" : "SSD/NVMe"
model = $4 ? $4 : "未知"
printf "%-8s %-8s %-6s %-15s %-6s %s\n",
"/dev/"$1, type, $3, model, ($2 == "1" ? "7200" : "N/A"), "正常"
}
'
) | column -t
# 2. 存储拓扑
echo -e "\n${GREEN}=== 存储拓扑 ===${NC}"
(
echo -e "设备\t\t类型\t容量\t挂载点\t\t文件系统\t使用率"
lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,RO,RM | awk '
BEGIN {
printf "%-8s %-8s %-6s %-15s %-8s %s\n",
"NAME", "TYPE", "SIZE", "MOUNTPOINT", "FSTYPE", "USE%"
}
$1 ~ /^[a-z]/ && $4 !~ /^\/run|\/sys|\/dev/ {
# 获取使用率
cmd = "df -h " $4 " | awk \"NR==2 {print \\$5}\" 2>/dev/null"
cmd | getline usage
close(cmd)
type = ($2 == "") ? "disk" : "part"
printf "%-8s %-8s %-6s %-15s %-8s %s\n",
"/dev/"$1, type, $3, ($4==""?"-":$4), ($2==""?"-":$2), (usage?usage:"-")
}
'
) | column -t
# 3. 分区详情
echo -e "\n${GREEN}=== 分区详情 ===${NC}"
(
echo -e "分区\t\t容量\t已用\t可用\t使用率\t挂载点\t\t文件系统"
df -hT | awk '
NR==1 {next}
$1 !~ /tmpfs|devtmpfs|overlay/ {
# 处理长设备名
dev = length($1)>15 ? substr($1,1,12)"..." : $1
printf "%-12s %-6s %-5s %-5s %-5s %-15s %s\n",
dev, $3, $4, $5, $6, $7, $2
}
' | sort -k6
) | column -t
# 4. LVM信息(如果有)
if command -v vgs >/dev/null && [ $(vgs 2>/dev/null | wc -l) -gt 1 ]; then
echo -e "\n${GREEN}=== LVM详细信息 ===${NC}"
# 卷组信息
echo -e "${BLUE}【卷组信息】${NC}"
vgs --units g | awk '
BEGIN {
printf "%-15s %-4s %-4s %-4s %-8s %-10s %-10s\n",
"VG", "#PV", "#LV", "#SN", "Attr", "VSize", "VFree"
}
NR>1 {
printf "%-15s %-4s %-4s %-4s %-8s %-10s %-10s\n",
$1, $2, $3, $4, $5, $6, $7
}
' | column -t
# 逻辑卷信息
echo -e "\n${BLUE}【逻辑卷信息】${NC}"
lvs --units g | awk '
BEGIN {
printf "%-15s %-15s %-8s %-8s %-8s %-8s %-8s\n",
"LV", "VG", "Attr", "LSize", "Data%", "Meta%", "Mount"
}
NR>1 {
# 获取挂载点
cmd = "df -h | grep \""$1"\" | awk \"{print \\$6}\""
cmd | getline mount
close(cmd)
printf "%-15s %-15s %-8s %-8s %-8s %-8s %-8s\n",
$1, $2, $3, $4, ($5?$5:"-"), ($6?$6:"-"), (mount?mount:"-")
}
' | column -t
fi
}
# RAID检查
check_raid() {
print_separator "RAID检查"
# 1. 检查软件RAID (mdadm)
if [ -f /proc/mdstat ]; then
echo -e "${BLUE}=== 软件RAID (mdadm) 信息 ===${NC}"
grep -A10 "^md" /proc/mdstat 2>/dev/null | awk '
/^md/ {
raid_device = $1
printf "设备: %s\n", raid_device
}
/raid[0-9]/ {
printf "级别: %s\n", $0
}
/blocks/ {
printf "大小: %s\n", $3
}
/\[[U_]+\]/ {
printf "状态: %s\n", $0
}
/sd[a-z]+\[[0-9]+\]/ {
disks = disks ? disks ", " $1 : $1
}
END {
if (disks) printf "成员磁盘: %s\n", disks
}
'
else
echo -e "${YELLOW}[信息] 未检测到软件RAID (mdadm)${NC}"
fi
# 2. 检查硬件RAID (MegaCLI/StorCLI/LSIutil)
echo -e "\n${BLUE}=== 硬件RAID 信息 ===${NC}"
# 检查MegaCLI (LSI MegaRAID)
if command -v MegaCli64 >/dev/null || command -v megacli >/dev/null; then
echo -e "${GREEN}检测到MegaRAID控制器${NC}"
CMD=$(command -v MegaCli64 || command -v megacli)
$CMD -LDInfo -Lall -aALL | awk '
/Virtual Drive:/ { printf "虚拟磁盘: %s\n", $3 }
/RAID Level/ { printf "RAID级别: %s\n", $4 }
/Size/ { printf "大小: %s %s\n", $3, $4 }
/State/ { printf "状态: %s\n", $3 }
/Number Of Drives/ { printf "磁盘数量: %s\n", $4 }
'
# 检查StorCLI (Broadcom/LSI)
elif command -v storcli >/dev/null; then
echo -e "${GREEN}检测到StorCLI控制器${NC}"
storcli /c0 show | awk '
/VD=Properties/ { vd=1; next }
vd && /TYPE/ { printf "RAID级别: %s\n", $3; vd=0 }
/Total Drives/ { printf "磁盘数量: %s\n", $3 }
'
# 检查HP Smart Array
elif command -v hpssacli >/dev/null || command -v hpacucli >/dev/null; then
echo -e "${GREEN}检测到HP SmartArray控制器${NC}"
CMD=$(command -v hpssacli || command -v hpacucli)
$CMD ctrl all show config | awk '
/logicaldrive/ { printf "逻辑磁盘: %s\n", $2 }
/raid/ { printf "RAID级别: %s\n", $1 }
/size/ { printf "大小: %s\n", $3 }
/Status/ { printf "状态: %s\n", $2 }
'
# 检查Dell PERC
elif [ -f /opt/MegaRAID/storcli/storcli64 ]; then
echo -e "${GREEN}检测到Dell PERC控制器${NC}"
/opt/MegaRAID/storcli/storcli64 /c0 show | awk '
/VD=Properties/ { vd=1; next }
vd && /TYPE/ { printf "RAID级别: %s\n", $3; vd=0 }
/Total Drives/ { printf "磁盘数量: %s\n", $3 }
'
else
echo -e "${YELLOW}[信息] 未检测到硬件RAID控制器${NC}"
echo -e "${YELLOW}[建议] 如需检测硬件RAID,请安装以下工具之一:${NC}"
echo -e " - MegaCli (LSI MegaRAID)"
echo -e " - storcli (Broadcom/LSI)"
echo -e " - hpssacli (HP SmartArray)"
fi
# 3. 检查设备映射器多路径 (DM-Multipath)
if command -v multipath >/dev/null && [ -f /etc/multipath.conf ]; then
echo -e "\n${BLUE}=== 多路径设备信息 ===${NC}"
multipath -ll 2>/dev/null | head -10
fi
# 4. 检查3ware RAID
if command -v tw_cli >/dev/null; then
echo -e "\n${BLUE}=== 3ware RAID 信息 ===${NC}"
tw_cli info | awk '
/^c[0-9]/ { printf "控制器: %s\n", $1 }
/u[0-9]/ { printf "磁盘: %s 状态: %s\n", $1, $2 }
'
fi
# 5. 通用磁盘检查
echo -e "\n${BLUE}=== 磁盘拓扑信息 ===${NC}"
lsblk -o NAME,ROTA,RM,SIZE,RO,TYPE,MOUNTPOINT 2>/dev/null | awk '
BEGIN {
printf "%-8s %-5s %-3s %-8s %-3s %-8s %-15s\n",
"设备", "旋转", "可移", "大小", "只读", "类型", "挂载点"
}
$1 ~ /^[a-z]/ {
printf "%-8s %-5s %-3s %-8s %-3s %-8s %-15s\n",
$1, ($2==1?"是":"否"), ($3==1?"是":"否"), $4, ($5==1?"是":"否"), $6, $7
}
' | column -t
}
# 网络检查
check_network() {
print_separator "网络检查"
# 1. 网络接口详情(对齐优化版)
echo -e "\n${GREEN}=== 网络接口详情 ===${NC}"
(
echo -e "接口名称 状态 IP地址 MAC地址 MTU 速率 接收 发送"
ip -o link show | awk -F': ' '$2 !~ /^lo/ {print $2}' | while read -r iface; do
# 跳过无效接口
if [ ! -d "/sys/class/net/$iface" ]; then
continue
fi
status=$(ip link show $iface | grep -q 'UP' && echo "UP " || echo "DOWN")
ipv4=$(ip -4 addr show $iface 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+' || echo "无IPv4")
ipv6=$(ip -6 addr show $iface 2>/dev/null | grep -oP '(?<=inet6\s)[\da-f:]+/\d+' | head -1 || echo "")
mac=$(ip link show $iface 2>/dev/null | grep -oP '(?<=link/ether\s)[\da-f:]+' || echo "无MAC")
mtu=$(ip link show $iface 2>/dev/null | grep -oP '(?<=mtu\s)\d+' || echo "1500")
# 获取网络速率
speed="未知 "
if [ -f "/sys/class/net/$iface/speed" ]; then
speed_num=$(cat "/sys/class/net/$iface/speed" 2>/dev/null)
[ -n "$speed_num" ] && speed=$(printf "%-7s" "${speed_num}Mb")
elif ethtool $iface 2>/dev/null | grep -q "Speed:"; then
speed=$(printf "%-7s" $(ethtool $iface 2>/dev/null | grep -oP '(?<=Speed:\s)\d+\w+'))
elif [ "$iface" = "docker0" ] || [ "$iface" = "br-"* ]; then
speed="10Gbps "
fi
# 获取流量统计
rx_bytes=$(cat "/sys/class/net/$iface/statistics/rx_bytes" 2>/dev/null || echo "0")
tx_bytes=$(cat "/sys/class/net/$iface/statistics/tx_bytes" 2>/dev/null || echo "0")
# 格式化流量
rx_human=$(numfmt --to=iec --suffix=B --format "%-8s" $rx_bytes 2>/dev/null || echo "0B ")
tx_human=$(numfmt --to=iec --suffix=B --format "%-8s" $tx_bytes 2>/dev/null || echo "0B ")
printf "%-20s %-5s %-30s %-18s %-6s %-7s %-10s %-10s\n" \
"$iface" "$status" "$ipv4" "$mac" "$mtu" "$speed" "$rx_human" "$tx_human"
# 显示IPv6地址(如果有)
if [ -n "$ipv6" ]; then
printf "%-20s %-5s %-30s %-18s %-6s %-7s %-10s %-10s\n" \
"" "" "$ipv6" "" "" "" "" ""
fi
done
)
# 2. 路由表信息(对齐优化版)
echo -e "\n${GREEN}=== 路由表信息 ===${NC}"
(
echo -e "目标网络 网关 接口 标志 跃点 来源"
ip route | awk '
/default/ {
via = ($3 == "via") ? $4 : $3
printf "%-15s %-15s %-16s %-8s %-8s %s\n",
"default", via, $5, "网关", ($7?$7:"-"), ($9?$9:"-")
next
}
{
via = ($3 == "via") ? $4 : "直连"
intf = ($3 == "via") ? $5 : $3
src = ""
for (i=6; i<=NF; i++) {
if ($i == "src") {
src = $(i+1)
break
}
}
printf "%-15s %-15s %-16s %-8s %-8s %s\n",
$1, via, intf, ($3 == "via" ? "网关" : "直连"), ($5?$5:"-"), src
}
'
)
# 3. DNS和连接信息(对齐优化版)
echo -e "\n${GREEN}=== DNS和连接信息 ===${NC}"
(
echo -e "DNS服务器 域名服务器"
grep -E 'nameserver|search' /etc/resolv.conf 2>/dev/null | awk '
/nameserver/ { printf "%-15s %s\n", $2, "解析服务器" }
/search/ { printf "%-15s %s\n", $2, "搜索域" }
'
echo -e "\n默认网关 接口 优先级"
ip route | awk '/default/ {
via = ($3 == "via") ? $4 : $3
printf "%-15s %-14s %s\n", via, $5, ($7?$7:"-")
}'
)
# 4. 网络连接统计(对齐优化版)
echo -e "\n${GREEN}=== 网络连接统计 ===${NC}"
ss -s | awk '
/Total:/ {printf "总连接数: %s\n", $2}
/TCP:/ {
gsub(/[^0-9,]/,"",$0)
split($0, tcp, ",")
printf "TCP状态:\n"
printf " 已建立: %s\n", tcp[1]
printf " 关闭中: %s\n", tcp[2]
printf " 孤儿: %s\n", tcp[3]
printf " 时间等待: %s\n", tcp[4]
}
/UDP:/ {printf "UDP: %s\n", $2}
/RAW:/ {printf "RAW: %s\n", $2}
'
# 5. 孤儿连接分析(对齐优化版)
echo -e "\n${YELLOW}=== 孤儿连接分析 ===${NC}"
orphan_count=$(ss -s | grep -oP '(?<=孤儿\s)\d+' || echo "0")
if [ "$orphan_count" -gt 100 ] 2>/dev/null; then
echo -e " ${RED}警告: 检测到大量孤儿连接($orphan_count)${NC}"
echo -e " 可能原因:"
echo -e " - 应用程序没有正确关闭连接"
echo -e " - 网络连接突然中断"
echo -e " - 系统TCP/IP栈配置问题"
echo -e "${YELLOW}建议操作:${NC}"
echo -e " - 检查应用程序日志"
echo -e " - 考虑调整内核参数:"
echo -e " sysctl -w net.ipv4.tcp_fin_timeout=30"
echo -e " sysctl -w net.ipv4.tcp_keepalive_time=1800"
elif [ "$orphan_count" -ge 0 ] 2>/dev/null; then
echo -e " 孤儿连接数量正常($orphan_count)"
else
echo -e " 无法获取孤儿连接信息"
fi
}
# 监听端口检查
check_listening() {
print_separator "监听检查"
# 1. 网络监听端口详情(完美修复版)
echo -e "\n${GREEN}=== 网络监听端口详情 ===${NC}"
(
echo -e "协议\t状态\t本地地址\t\t进程信息\t\t服务"
ss -tulnp 2>/dev/null | awk '
BEGIN {
proto_map["tcp"] = "TCP";
proto_map["udp"] = "UDP";
}
NR>1 {
# 提取协议和状态
proto = proto_map[$1];
state = $2;
# 提取并格式化本地地址
local = $5;
if (local ~ /:/) {
sub(/.*:/, ":", local);
sub(/]$/, "", local);
if (local == ":*") local = "*";
}
# 提取并清理进程信息
process = $7;
gsub(/users:\(\(\"|\"\).*/, "", process);
split(process, proc_parts, "\",\"");
pid_name = proc_parts[1] "/" proc_parts[2];
# 获取服务名称
port = $5;
sub(/^.*:/, "", port);
sub(/].*$/, "", port);
service = "-";
if (port ~ /^[0-9]+$/) {
"grep -w ^" port " /etc/services 2>/dev/null | head -1 | cut -f1" | getline service;
close("grep -w ^" port " /etc/services 2>/dev/null | head -1 | cut -f1");
}
printf "%s\t%s\t%s\t\t%s\t\t%s\n",
proto, state, local, pid_name, service;
}
' | sort -k3
) | column -t -s $'\t'
# 2. 高危端口检测(无错误版)
echo -e "\n${RED}=== 高危端口检测 ===${NC}"
(
echo -e "协议\t端口\t风险等级\t绑定地址\t\t服务\t\t建议"
# 高危端口定义
high_risk_ports=(
"22 tcp SSH 高危 限制访问IP或使用密钥认证"
"23 tcp Telnet 高危 建议禁用"
"21 tcp FTP 高危 使用SFTP替代"
"25 tcp SMTP 中危 配置认证和加密"
"53 udp DNS 中危 限制查询范围"
"3306 tcp MySQL 高危 限制访问IP"
"3389 tcp RDP 高危 使用VPN访问"
)
# 检查实际开放的端口
for port_info in "${high_risk_ports[@]}"; do
read port proto service risk_level suggestion <<< "$port_info"
if ss -lntu | grep -q "$proto.*:$port "; then
bind_info=$(ss -lntu | grep "$proto.*:$port " | head -1 | awk '{print $5}')
if [[ "$bind_info" == *"["*"]"* ]]; then
# IPv6地址处理
bind_ip=$(echo "$bind_info" | sed 's/.*\[\(.*\)\]:.*/\1/')
[ -z "$bind_ip" ] && bind_ip="::"
else
# IPv4地址处理
bind_ip=$(echo "$bind_info" | cut -d':' -f1)
[ -z "$bind_ip" ] && bind_ip="0.0.0.0"
[ "$bind_ip" == "*" ] && bind_ip="0.0.0.0"
fi
printf "%s\t%s\t%s\t\t%s\t\t%s\t%s\n" \
"$proto" "$port" "$risk_level" "$bind_ip" "$service" "$suggestion"
fi
done
) | column -t -s $'\t'
# 3. 异常连接检测(优化版)
echo -e "\n${YELLOW}=== 异常连接检测 ===${NC}"
(
echo -e "协议\t本地地址\t\t远程地址\t\t状态\t\t进程"
ss -atnp 2>/dev/null | awk '
$1 ~ /tcp|udp/ && $2 !~ /LISTEN|UNCONN/ {
# 提取本地和远程地址
split($5, local, ":");
split($6, remote, ":");
# 提取进程信息
process = $7;
gsub(/users:\(\(\"|\"\).*/, "", process);
split(process, proc_parts, "\",\"");
pid_name = proc_parts[1] "/" proc_parts[2];
printf "%s\t%s:%s\t%s:%s\t%s\t%s\n",
$1, local[1], local[2], remote[1], remote[2], $2, pid_name;
}
' | head -10
) | column -t -s $'\t'
}
# 进程检查
check_processes() {
print_separator "进程检查"
# 1. 内存占用TOP10(修复版)
echo -e "\n${BLUE}=== 内存占用TOP10 (物理内存) ===${NC}"
mem_processes=$(ps -eo pid,%mem,rss,comm --sort=-rss 2>/dev/null | awk -v yellow="$YELLOW" -v nc="$NC" '
BEGIN {
printf "%-6s %-5s %-10s %s\n", "PID", "%MEM", "RSS(MB)", "COMMAND"
count=0
}
NR>1 && $1 != "PID" && count<10 {
rss_mb = $3/1024
# 处理异常值
if (rss_mb == 0 && $3 > 0) rss_mb = $3
printf "%-6s %-5s %-10.1f %s\n",
$1, $2, rss_mb, $4
count++
}
END {
if (count == 0) {
print " [无活跃进程 - 显示历史记录]"
cmd = "ps -eo pid,%mem,rss,comm --sort=-rss --no-headers | head -10 | awk '\''{printf \"%-6s %-5s %-10.1f %s\\n\", $1, $2, $3/1024, $4}'\''"
system(cmd)
}
}
')
echo "$mem_processes" | column -t
# 2. CPU占用TOP10(修复版)
echo -e "\n${BLUE}=== CPU占用TOP10 ===${NC}"
cpu_processes=$( (ps -eo pid,user,pcpu,pmem,time,comm --sort=-pcpu 2>/dev/null || ps aux 2>/dev/null) | awk -v red="$RED" -v nc="$NC" '
BEGIN {
printf "%-6s %-8s %-5s %-5s %-11s %s\n",
"PID", "USER", "%CPU", "%MEM", "TIME", "COMMAND"
count=0
}
NR<=11 && $0 !~ /PID|USER/ && count<10 {
# 处理不同ps格式
if (NF == 6) {
pid=$1; user=$2; pcpu=$3; pmem=$4; time=$5; cmd=$6
} else if (NF >= 11) {
pid=$1; user=$2; pcpu=$3; pmem=$4; time=$10; cmd=$11
for(i=12;i<=NF;i++) cmd=cmd" "$i
}
# 跳过标题行和全零行
if (pid != "PID" && (pcpu+0 > 0 || NR == 2)) {
printf "%-6s %-8s %-5s %-5s %-11s %s\n",
pid, user, pcpu+0, pmem+0, time, cmd
count++
}
}
END {
if (count == 0) {
print " [无CPU占用进程 - 显示历史记录]"
cmd = "(ps -eo pid,user,pcpu,pmem,time,comm --sort=-pcpu --no-headers || ps aux --no-headers) | head -10 | awk '\''{printf \"%-6s %-8s %-5s %-5s %-11s %s\\n\", $1, $2, $3, $4, $5, $6}'\''"
system(cmd)
}
}
')
echo "$cpu_processes" | column -t
# 3. 添加进程历史记录
echo -e "\n${BLUE}=== 最近启动的进程 ===${NC}"
recent_procs=$(ps -eo pid,user,lstart,cmd --sort=-start_time 2>/dev/null | head -10 | awk '
BEGIN {
printf "%-6s %-8s %-20s %s\n", "PID", "USER", "启动时间", "命令"
}
NR>1 {
"date -d \""$3" "$4" "$5" "$6"\" \"+%Y-%m-%d %H:%M:%S\"" | getline start_time
close("date -d \""$3" "$4" "$5" "$6"\" \"+%Y-%m-%d %H:%M:%S\"")
printf "%-6s %-8s %-20s %s\n", $1, $2, start_time, $NF
}
')
[ -n "$recent_procs" ] && echo "$recent_procs" | column -t || echo " 无法获取进程历史记录"
}
# 服务检查
check_services() {
print_separator "服务检查"
# 1. 运行中的服务(修复日期问题版)
echo -e "\n${GREEN}=== 运行中的服务 ===${NC}"
(
echo -e "状态\t服务名称\t\t运行时间\t内存占用\t主PID\t描述"
systemctl list-units --type=service --state=running --no-pager --no-legend 2>/dev/null | \
while read -r line; do
service=$(echo "$line" | awk '{print $1}')
status=$(systemctl is-active "$service")
# 修复日期解析问题
activetime=$(systemctl show "$service" --property=ActiveEnterTimestampMonotonic | cut -d= -f2)
if [ -n "$activetime" ]; then
uptime=$(awk -v ticks="$activetime" 'BEGIN {
now = systime();
uptime = now - (ticks / 1000000);
print strftime("%Y-%m-%d %H:%M:%S", uptime);
}')
else
uptime="N/A"
fi
memory=$(systemctl show "$service" --property=MemoryCurrent | cut -d= -f2)
pid=$(systemctl show "$service" --property=MainPID | cut -d= -f2)
desc=$(systemctl show "$service" --property=Description | cut -d= -f2 | cut -c1-30)
# 格式化内存显示
if [ "$memory" -ge 0 ] 2>/dev/null; then
memory=$(numfmt --to=iec --suffix=B "$memory")
else
memory="N/A"
fi
printf "✓\t%-20s\t%s\t%s\t%s\t%s\n" \
"$service" "$uptime" "$memory" "$pid" "$desc"
done
) | column -t -s $'\t'
# 2. 失败的服务(保持不变)
echo -e "\n${RED}=== 失败的服务 ===${NC}"
failed_services=$(systemctl list-units --type=service --state=failed --no-pager --no-legend 2>/dev/null)
if [ -z "$failed_services" ]; then
echo -e " ${GREEN}[无失败服务]${NC}"
else
(
echo -e "状态\t服务名称\t\t错误信息\t\t\t最后日志"
echo "$failed_services" | while read -r line; do
service=$(echo "$line" | awk '{print $1}')
status=$(systemctl is-active "$service")
error=$(systemctl status "$service" | grep -i "error\|failed" | head -1 | sed 's/ *//g')
journal=$(journalctl -u "$service" -n 1 --no-pager | grep -v "^--" | cut -c1-50)
printf "✗\t%-20s\t%-30s\t%s\n" \
"$service" "${error:-N/A}" "${journal:-N/A}"
done
) | column -t -s $'\t'
fi
# 3. 高资源占用的服务(保持不变)
echo -e "\n${YELLOW}=== 高资源占用服务 ===${NC}"
(
echo -e "服务名称\tCPU%\t内存\t读写IO\t连接数"
systemctl list-units --type=service --state=running --no-pager --no-legend 2>/dev/null | \
while read -r line; do
service=$(echo "$line" | awk '{print $1}')
pid=$(systemctl show "$service" --property=MainPID | cut -d= -f2)
if [ "$pid" -gt 0 ] 2>/dev/null; then
cpu=$(ps -p "$pid" -o %cpu --no-headers 2>/dev/null | awk '{print $1}')
memory=$(ps -p "$pid" -o rss --no-headers 2>/dev/null | awk '{print $1/1024}')
io_read="N/A"
io_write="N/A"
if [ "$(id -u)" -eq 0 ]; then
io_stats=$(grep '^read_bytes\|^write_bytes' "/proc/$pid/io" 2>/dev/null | awk '{print $2/1024}')
if [ -n "$io_stats" ]; then
io_read=$(echo "$io_stats" | head -1)
io_write=$(echo "$io_stats" | tail -1)
fi
fi
connections=$(lsof -p "$pid" 2>/dev/null | grep -c ESTABLISHED || echo "N/A")
if [ -n "$cpu" ] && [ "$cpu" != "0.0" ] || [ "$memory" -gt 10 ] 2>/dev/null; then
printf "%-20s\t%.1f%%\t%.1fM\t%.1fK/%.1fK\t%s\n" \
"$service" "${cpu:-0}" "${memory:-0}" "${io_read:-0}" "${io_write:-0}" "${connections:-0}"
fi
fi
done | sort -k2 -nr | head -10
) | column -t
# 4. 关键服务检查(修复版)
echo -e "\n${BLUE}=== 关键服务状态 ===${NC}"
important_services=(
"sshd.service"
"crond.service"
"network.target"
"dbus.service"
"rsyslog.service"
"docker.service"
"containerd.service"
"firewalld.service"
"NetworkManager.service"
)
(
echo -e "服务名称\t状态\t子状态\t是否启用\t启动时间"
for service in "${important_services[@]}"; do
if systemctl list-unit-files | grep -q "$service"; then
status=$(systemctl is-active "$service" 2>/dev/null || echo "N/A")
substate=$(systemctl show "$service" --property=SubState | cut -d= -f2)
enabled=$(systemctl is-enabled "$service" 2>/dev/null || echo "N/A")
# 使用更可靠的启动时间获取方法
activetime=$(systemctl show "$service" --property=ActiveEnterTimestampMonotonic | cut -d= -f2)
if [ -n "$activetime" ]; then
uptime=$(awk -v ticks="$activetime" 'BEGIN {
now = systime();
uptime = now - (ticks / 1000000);
print strftime("%H:%M:%S", uptime);
}')
else
uptime="N/A"
fi
printf "%-20s\t%s\t%s\t%s\t%s\n" \
"$service" "$status" "$substate" "$enabled" "$uptime"
fi
done
) | column -t
}
# 用户检查
check_users() {
print_separator "用户检查"
# 1. 显示passwd文件修改时间
if [ -f /etc/passwd ]; then
passwd_mtime=$(stat -c "%y" /etc/passwd 2>/dev/null | cut -d. -f1)
passwd_seconds=$(( $(date +%s) - $(date +%s -r /etc/passwd 2>/dev/null) ))
days=$(( passwd_seconds / 86400 ))
hours=$(( (passwd_seconds % 86400) / 3600 ))
echo -e "/etc/passwd 最后修改时间:${passwd_mtime} (${days} 天 ${hours} 小时前)\n"
else
echo -e "无法获取/etc/passwd信息\n"
fi
# 2. 特权用户检查
echo -e "特权用户\n--------"
awk -F: '$3 == 0 {print $1}' /etc/passwd 2>/dev/null || echo "无"
# 3. 用户列表
echo -e "\n用户列表\n--------"
(
echo -e "用户名 UID GID HOME SHELL 最后一次登录"
getent passwd 2>/dev/null | while IFS=: read -r user _ uid gid _ home shell _; do
last_login=$(last -n 1 -F "$user" 2>/dev/null | awk 'NR==1 && !/wtmp/{printf "%s_%s", $5, $6}')
[ -z "$last_login" ] && last_login="从未登录"
printf "%s %s %s %s %s %s\n" "$user" "$uid" "$gid" "$home" "$shell" "$last_login"
done
) | column -t
# 4. 空密码用户检查
echo -e "\n空密码用户\n----------"
(
awk -F: '($2 == "" || $2 == "!") {print $1}' /etc/shadow 2>/dev/null || echo "无"
)
# 5. 相同ID检查
echo -e "\n相同ID的用户\n------------"
echo -e "[相同UID]"
(getent passwd | cut -d: -f3 | sort | uniq -d | while read uid; do
grep -w "$uid" /etc/passwd | cut -d: -f1 | paste -sd ","
done) || echo "无"
echo -e "\n[相同GID]"
(getent passwd | cut -d: -f4 | sort | uniq -d | while read gid; do
grep -w "$gid" /etc/passwd | cut -d: -f1 | paste -sd ","
done) || echo "无"
}
#登录检查
check_logins() {
print_separator "登录检查"
# 获取并格式化登录信息
(
echo -e "用户\t终端\tIP地址\t登录时间\t状态"
last -n 10 -F -i -w | awk -v yellow="$YELLOW" -v nc="$NC" '
BEGIN {
OFS="\t"
}
NR>1 && !/^wtmp|^$|^reboot|^shutdown|^runlevel/ {
user = $1
tty = ($2 ~ /pts|tty|:0/) ? $2 : "other"
ip = ($3 ~ /^[0-9]/) ? $3 : "-"
# 标准化时间格式
time_str = $5" "$6" "$7" "$8
# 处理状态信息
if ($0 ~ /still logged in/) {
status = yellow "仍在线" nc
is_active = 1
}
else if ($0 ~ /down/) {
status = "已下线"
}
else {
match($0, /\(([^)]+)\)/, duration)
status = duration[1] ? "(" duration[1] ")" : "未知"
}
printf "%s\t%s\t%s\t%s\t%s\n", user, tty, ip, time_str, status
}
/^reboot|^shutdown/ {
printf "reboot\tsystem boot\t-\t%s %s %s %s\t系统重启\n", $5, $6, $7, $8
}
'
) | column -t -s $'\t'
# 准确统计活跃会话(使用who命令)
echo -e "\n${BLUE}当前登录用户数:${NC}"
active_users=$(who -u | awk '!/^USER/ && $7 != "." {print $1}' | wc -l)
echo " 总计: $active_users 个活跃会话"
# 显示当前活跃会话详情(可选)
if [ "$active_users" -gt 0 ]; then
echo -e "\n${BLUE}当前活跃会话:${NC}"
who -u | awk '!/^USER/ && $7 != "." {
printf " %-8s %-12s %-15s %s\n", $1, $2, $6, $3" "$4
}'
fi
}
# 安全检查
check_security() {
print_separator "安全检查"
echo -e "\nSSH配置:"
echo -e " PermitRootLogin: $(grep -i PermitRootLogin /etc/ssh/sshd_config | grep -v '#' | awk '{print $2}')"
echo -e "\n防火墙状态:"
if systemctl is-active firewalld >/dev/null; then
echo -e " ${GREEN}✓${NC} firewalld (active)"
else
echo -e " ${YELLOW}⚠${NC} firewalld (inactive)"
fi
}
#计划任务检查
check_cron() {
print_separator "计划任务检查"
# 系统级计划任务(带高亮)
echo -e "\n$(highlight "info" "■■■ 系统计划任务 ■■■")"
(
echo -e "类型\t权限\t所有者\t大小\t最后修改\t\t任务路径"
find /etc/cron* /var/spool/cron -type f -exec ls -lh --time-style=long-iso {} + 2>/dev/null | \
awk -v yellow="$YELLOW" -v red="$RED" -v cyan="$CYAN" -v nc="$NC" '{
path=$NF
if (path ~ /cron\.d/) {type="cron.d"; color=cyan}
else if (path ~ /cron\.daily/) {type="daily"; color=""}
else if (path ~ /cron\.hourly/) {type="hourly"; color=""}
else if (path ~ /cron\.monthly/) {type="monthly"; color=""}
else if (path ~ /cron\.weekly/) {type="weekly"; color=""}
else if (path ~ /var\/spool\/cron/) {type="user"; color=yellow}
else {type="other"; color=""}
# 高亮关键文件
if (path ~ /(cron\.(deny|allow)|anacron)/) {color=red}
printf "%s%s%s\t%s\t%s\t%s\t%s\t%s%s%s\n",
color, type, nc, $1, $3, $5, $6" "$7, color, path, nc
}'
) | column -t -s $'\t' | head -n 15
# 用户级计划任务(带高亮)
echo -e "\n$(highlight "info" "■■■ 用户计划任务 ■■■")"
user_crons=$(for user in $(cut -f1 -d: /etc/passwd); do
crontab -l -u "$user" 2>/dev/null | grep -v "^#" | \
awk -v user="$user" -v yellow="$YELLOW" -v nc="$NC" '{
# 高亮root用户和危险命令
if (user == "root") {user_color="\033[1;31m"} else {user_color=""}
if ($0 ~ /(shutdown|rm\s+-|chmod\s+777)/) {cmd_color="\033[1;31m"} else {cmd_color=""}
printf "%s%s%s\t%s%s%s\n", user_color, user, nc, cmd_color, $0, nc
}'
done)
if [ -n "$user_crons" ]; then
echo -e "$(highlight "special" "用户")\t\t$(highlight "special" "任务内容")"
echo -e "$user_crons" | column -t -s $'\t'
else
highlight "success" "未检测到用户计划任务"
fi
}
#自启动检查
check_autostart() {
print_separator "自启动检查"
# 系统服务自启动(带状态高亮)
echo -e "\n$(highlight "info" "■■■ 系统服务自启动 ■■■")"
(
echo -e "状态\t服务名称"
systemctl list-unit-files --type=service --state=enabled 2>/dev/null | \
awk -v green="$GREEN" -v red="$RED" -v nc="$NC" 'NR>1 && !/^@/ {
if ($2 == "enabled") {
status = green"✓"nc
# 高亮不安全服务
if ($1 ~ /(telnet|ftp|rsh)/) {service=red$1nc}
else {service=$1}
} else {
status = red"✗"nc
service=$1
}
printf "%s\t%s\n", status, service
}'
) | column -t -s $'\t' | head -n 10
# 用户级自启动项(带高亮)
echo -e "\n$(highlight "info" "■■■ 用户级自启动项 ■■■")"
desktop_files=$(find /etc/xdg/autostart /usr/share/autostart ~/.config/autostart -name "*.desktop" 2>/dev/null)
if [ -n "$desktop_files" ]; then
echo "$desktop_files" | xargs -n1 basename 2>/dev/null | \
awk -v magenta="$MAGENTA" -v nc="$NC" '{print " " magenta"▪" nc " " $0}'
else
highlight "success" " 未检测到用户自启动项"
fi
# 定时任务(带危险命令高亮)
echo -e "\n$(highlight "info" "■■■ 定时任务 ■■■")"
sys_crontab=$(grep -v "^#" /etc/crontab 2>/dev/null)
user_crontab=$(crontab -l 2>/dev/null | grep -v "^#")
if [ -n "$sys_crontab" ] || [ -n "$user_crontab" ]; then
[ -n "$sys_crontab" ] && echo -e "$(highlight "warn" "系统定时任务:")" && \
echo "$sys_crontab" | awk -v red="$RED" -v nc="$NC" '{
if ($0 ~ /(shutdown|rm\s+-|chmod\s+777)/) {print red$0nc}
else {print}
}'
[ -n "$user_crontab" ] && echo -e "$(highlight "warn" "用户定时任务:")" && \
echo "$user_crontab" | awk -v red="$RED" -v nc="$NC" '{
if ($0 ~ /(shutdown|rm\s+-|chmod\s+777)/) {print red$0nc}
else {print}
}'
else
highlight "success" "未检测到定时任务"
fi
}
#密码检查
check_password() {
print_separator "密码检查"
# 密码过期检查(修复版)
echo -e "\n${CYAN}密码过期检查${NC}"
echo -e "------------"
(
echo -e "用户名\t\t过期状态"
getent passwd | awk -F: '$7 !~ /nologin|false/ {print $1}' | while read -r user; do
# 修复密码状态检测逻辑
if grep -q "^${user}:[^\!*]" /etc/shadow 2>/dev/null; then
expiry=$(chage -l "$user" 2>/dev/null | awk -F": " '/Password expires/{print $2}')
if [ "$expiry" == "never" ]; then
echo -e "$user\t\t永不过期"
elif [ "$expiry" == "password must be changed" ] || [ "$expiry" == "must be changed" ]; then
echo -e "$user\t\t${RED}必须修改${NC}"
elif [ -n "$expiry" ]; then
echo -e "$user\t\t$expiry"
else
echo -e "$user\t\t${YELLOW}密码已设置${NC}"
fi
else
echo -e "$user\t\t${RED}无密码/已锁定${NC}"
fi
done
) | column -t -s $'\t'
# 密码策略检查(修复版)
echo -e "\n${CYAN}密码策略检查${NC}"
echo -e "------------"
(
echo -e "策略项\t\t当前值\t建议值\t合规性"
# 获取策略值(带默认值)
max_days=$(grep "^PASS_MAX_DAYS" /etc/login.defs 2>/dev/null | awk '{print $2}')
[ -z "$max_days" ] && max_days=99999
min_days=$(grep "^PASS_MIN_DAYS" /etc/login.defs 2>/dev/null | awk '{print $2}')
[ -z "$min_days" ] && min_days=0
min_len=$(grep "^PASS_MIN_LEN" /etc/login.defs 2>/dev/null | awk '{print $2}')
[ -z "$min_len" ] && min_len=$(grep "^minlen" /etc/security/pwquality.conf 2>/dev/null | awk '{print $3}')
[ -z "$min_len" ] && min_len=0
warn_age=$(grep "^PASS_WARN_AGE" /etc/login.defs 2>/dev/null | awk '{print $2}')
[ -z "$warn_age" ] && warn_age=7
# 修复整数比较错误
is_compliant() {
local current=$1
local recommended=$2
if [ "$current" -eq "$recommended" ] 2>/dev/null; then
echo -e "${GREEN}符合${NC}"
elif [ "$current" -lt "$recommended" ] 2>/dev/null; then
echo -e "${GREEN}更严格${NC}"
else
echo -e "${RED}不符合${NC}"
fi
}
echo -e "PASS_MAX_DAYS\t$max_days\t90\t$(is_compliant "$max_days" 90)"
echo -e "PASS_MIN_DAYS\t$min_days\t7\t$(is_compliant "$min_days" 7)"
echo -e "PASS_MIN_LEN\t$min_len\t12\t$(is_compliant "$min_len" 12)"
echo -e "PASS_WARN_AGE\t$warn_age\t14\t$(is_compliant "$warn_age" 14)"
) | column -t -s $'\t'
# 弱密码用户检查(修复版)
echo -e "\n${CYAN}弱密码用户检查${NC}"
echo -e "------------"
# 尝试使用faillock(现代系统)
if [ -x "$(command -v faillock)" ]; then
fails=$(faillock 2>/dev/null | awk '
/^>/ {
user = substr($1, 2) # 去掉开头的>
attempts = $2
print " ⚠ " user " (失败次数: " attempts ")"
}')
[ -n "$fails" ] && echo -e "${YELLOW}登录失败用户:${NC}\n$fails" || echo " 无失败记录"
# 回退到pam_tally2(旧系统)
elif [ -x "$(command -v pam_tally2)" ]; then
fails=$(pam_tally2 2>/dev/null | awk '
NR>1 && !/^$/ {
print " ⚠ " $1 " (失败次数: " $2 ")"
}')
[ -n "$fails" ] && echo -e "${YELLOW}登录失败用户:${NC}\n$fails" || echo " 无失败记录"
# 如果都没有则检查btmp日志
elif [ -f "/var/log/btmp" ]; then
echo -e "${YELLOW}最近登录失败记录:${NC}"
lastb -a 2>/dev/null | head -n 5 | awk '
NR>1 && !/^btmp/ {
print " ⚠ " $1 " 从 " $3 " 于 " $4 " " $5 " " $6 " " $7
}'
else
echo " 未找到登录失败记录工具"
fi
# 空密码用户检查(精确版)
echo -e "\n${CYAN}空密码用户检查${NC}"
echo -e "------------"
empty_pass=$(awk -F: '($2 == "" || $2 == "!") {print $1}' /etc/shadow 2>/dev/null)
if [ -n "$empty_pass" ]; then
echo -e "${RED}⚠ 存在空密码/锁定用户:${NC}"
echo "$empty_pass" | awk '{print " " $0}'
else
echo -e "${GREEN}✓ 未发现空密码用户${NC}"
fi
# 密码哈希算法检查
echo -e "\n${CYAN}密码哈希算法${NC}"
echo -e "------------"
if grep -q "^ENCRYPT_METHOD SHA512" /etc/login.defs 2>/dev/null; then
echo -e "${GREEN}✓ 使用SHA512加密${NC}"
elif grep -q "^ENCRYPT_METHOD " /etc/login.defs 2>/dev/null; then
echo -e "${YELLOW}⚠ 当前使用$(grep "^ENCRYPT_METHOD" /etc/login.defs | awk '{print $2}')加密${NC}"
else
echo -e "${YELLOW}⚠ 未明确指定加密方法${NC}"
fi
}
#sudoers检查
check_sudoers() {
print_separator "Sudoers检查"
# 1. 主sudoers配置检查(增强解析逻辑)
echo -e "\n${CYAN}=== Sudoers主配置 ===${NC}"
(
echo -e "类型\t名称\t权限"
awk '! /^#|^Defaults|^$/ && !/^@include/ && NF>=3 {
type = ($1 ~ /^%/) ? "用户组" : "用户"
name = $1
$1 = ""
gsub(/^[ \t]+/, "", $0)
print type "\t" name "\t" $0
}' /etc/sudoers 2>/dev/null
) | column -t -s $'\t'
# 2. 包含的配置文件检查(递归检查)
echo -e "\n${CYAN}=== 包含的配置文件 ===${NC}"
includes=$(grep "^@include" /etc/sudoers 2>/dev/null | awk '{print $2}')
if [ -n "$includes" ]; then
(
echo -e "文件路径\t类型\t名称\t权限"
while read -r file; do
[ -f "$file" ] && awk '! /^#|^Defaults|^$/ && NF>=3 {
type = ($1 ~ /^%/) ? "用户组" : "用户"
name = $1
$1 = ""
gsub(/^[ \t]+/, "", $0)
print FILENAME "\t" type "\t" name "\t" $0
}' "$file" 2>/dev/null
done <<< "$includes"
) | column -t -s $'\t'
else
echo "未找到包含的配置文件"
fi
# 3. sudoers.d目录检查(增强错误处理)
echo -e "\n${CYAN}=== /etc/sudoers.d/配置 ===${NC}"
if [ -d "/etc/sudoers.d" ]; then
(
echo -e "文件\t类型\t名称\t权限"
find /etc/sudoers.d -type f -name "*.conf" -exec awk '! /^#|^Defaults|^$/ && NF>=3 {
type = ($1 ~ /^%/) ? "用户组" : "用户"
name = $1
$1 = ""
gsub(/^[ \t]+/, "", $0)
print FILENAME "\t" type "\t" name "\t" $0
}' {} + 2>/dev/null
) | column -t -s $'\t' | head -n 5
else
echo "未找到/etc/sudoers.d目录"
fi
# 4. 无需密码的sudo权限(精确匹配)
echo -e "\n${RED}=== 无需密码的sudo权限(NOPASSWD) ===${NC}"
nopasswd=$(grep -rEh "NOPASSWD:" /etc/sudoers /etc/sudoers.d/ 2>/dev/null | awk '!seen[$0]++ {
gsub(/[ \t]+/, " ", $0)
split($0, parts, "NOPASSWD:")
printf "%s\t%s\n", parts[1], "NOPASSWD:" parts[2]
}')
if [ -n "$nopasswd" ]; then
echo -e "配置来源\t权限"
echo "$nopasswd" | column -t -s $'\t'
else
echo "未配置NOPASSWD权限"
fi
# 5. sudo组用户检查(增强兼容性)
echo -e "\n${YELLOW}=== 通过sudo组获得权限的用户 ===${NC}"
sudo_users=$(getent group sudo 2>/dev/null | cut -d: -f4 | tr ',' '\n' | sort | uniq)
if [ -n "$sudo_users" ]; then
echo "$sudo_users" | awk '{print " " $0}'
else
echo " sudo组中没有用户"
fi
# 6. 用户详细权限检查(优化性能)
echo -e "\n${CYAN}=== 用户详细sudo权限 ===${NC}"
checked_users=0
for user in $(getent passwd | cut -d: -f1); do
# 跳过root和系统用户
[[ "$user" == "root" ]] || [[ "$(getent passwd "$user" | cut -d: -f3)" -lt 1000 ]] && continue
sudo -U "$user" -l 2>/dev/null | grep -q "may run the following commands" && {
echo -n " $user: "
sudo -U "$user" -l | awk '/may run/,/^$/{if($0 !~ /may run/)print}' | tr '\n' ' '
echo ""
((checked_users++))
[ $checked_users -ge 3 ] && break # 限制输出数量
}
done
[ $checked_users -eq 0 ] && echo " 未检测到用户特殊sudo权限"
}
#JDK检查
check_jdk() {
print_separator "JDK检查"
# 1. 检查JAVA_HOME环境变量
echo -e "\n${CYAN}=== JAVA_HOME环境变量 ===${NC}"
if [ -n "$JAVA_HOME" ]; then
echo -e "JAVA_HOME=\"$JAVA_HOME\""
if [ -d "$JAVA_HOME" ]; then
echo -e "${GREEN}✓ 路径存在${NC}"
else
echo -e "${RED}✗ 路径不存在${NC}"
fi
else
echo -e "JAVA_HOME=\"\""
echo -e "${YELLOW}⚠ 未设置JAVA_HOME环境变量${NC}"
fi
# 2. 检查java命令路径
echo -e "\n${CYAN}=== Java可执行文件 ===${NC}"
java_path=$(command -v java 2>/dev/null)
if [ -n "$java_path" ]; then
echo -e "java路径: $java_path"
echo -e "版本信息:"
java -version 2>&1 | head -n 1 | awk -F '"' '{print $2}'
else
echo -e "${RED}✗ 未找到java命令${NC}"
fi
# 3. 检查安装的JDK版本
echo -e "\n${CYAN}=== 已安装的JDK版本 ===${NC}"
if [ -d "/usr/lib/jvm" ]; then
echo -e "${GREEN}系统JDK安装目录:/usr/lib/jvm${NC}"
ls -l /usr/lib/jvm | awk '/jdk|java/ && !/^d/ {print $9}'
else
echo -e "${YELLOW}⚠ 未找到标准JDK安装目录${NC}"
fi
# 4. 检查备选JDK路径
echo -e "\n${CYAN}=== 备选JDK路径检查 ===${NC}"
common_paths=(
"/usr/java"
"/opt/java"
"/Library/Java/JavaVirtualMachines"
"C:\Program Files\Java"
)
found=0
for path in "${common_paths[@]}"; do
if [ -d "$path" ]; then
echo -e "${GREEN}找到JDK目录: $path${NC}"
ls -l "$path" | awk '/jdk|java/ && !/^d/ {print $9}'
found=1
fi
done
[ $found -eq 0 ] && echo -e "${YELLOW}⚠ 未在常见路径找到JDK${NC}"
# 5. 检查Java进程
echo -e "\n${CYAN}=== 运行的Java进程 ===${NC}"
java_processes=$(ps aux | grep java | grep -v grep)
if [ -n "$java_processes" ]; then
echo -e "${YELLOW}运行的Java进程:${NC}"
echo "$java_processes" | awk '{print $1 "\t" $11 "\t" $12}'
else
echo -e "${GREEN}✓ 没有运行的Java进程${NC}"
fi
}
#防火墙检查
check_firewall() {
print_separator "防火墙检查"
# 1. 检查iptables状态
echo -e "\n${CYAN}=== iptables状态 ===${NC}"
if [ -x "$(command -v iptables)" ]; then
iptables_status=$(iptables -L 2>/dev/null | grep -q -v "Chain INPUT (policy ACCEPT)" && echo "active" || echo "inactive")
echo -e "iptables: $iptables_status"
else
echo -e "${YELLOW}iptables: 未安装${NC}"
fi
# 2. 检查iptables配置文件
echo -e "\n${CYAN}=== iptables配置文件 ===${NC}"
if [ -f "/etc/sysconfig/iptables" ]; then
echo -e "/etc/sysconfig/iptables"
echo -e "-----------------------"
cat /etc/sysconfig/iptables | grep -v "^#" | sed '/^$/d'
else
echo -e "${YELLOW}未找到/etc/sysconfig/iptables文件${NC}"
fi
# 3. 检查firewalld状态
echo -e "\n${CYAN}=== firewalld状态 ===${NC}"
if [ -x "$(command -v firewall-cmd)" ]; then
firewall_status=$(systemctl is-active firewalld 2>/dev/null)
if [ "$firewall_status" = "active" ]; then
echo -e "firewalld: ${GREEN}active${NC}"
echo -e "默认区域: $(firewall-cmd --get-default-zone)"
else
echo -e "firewalld: ${YELLOW}inactive${NC}"
fi
else
echo -e "${YELLOW}firewalld: 未安装${NC}"
fi
# 4. 检查ufw状态(Ubuntu)
echo -e "\n${CYAN}=== ufw状态 ===${NC}"
if [ -x "$(command -v ufw)" ]; then
ufw_status=$(ufw status | grep "Status:")
if [[ "$ufw_status" == *"active"* ]]; then
echo -e "ufw: ${GREEN}active${NC}"
echo -e "规则:"
ufw status numbered | tail -n +4
else
echo -e "ufw: ${YELLOW}inactive${NC}"
fi
else
echo -e "${YELLOW}ufw: 未安装${NC}"
fi
# 5. 检查开放的端口
echo -e "\n${CYAN}=== 开放端口检查 ===${NC}"
if [ -x "$(command -v ss)" ]; then
echo -e "监听端口:"
ss -tulnp | awk 'NR>1 {print $5 "\t" $1 "\t" $6}'
elif [ -x "$(command -v netstat)" ]; then
echo -e "监听端口:"
netstat -tulnp | awk 'NR>2 {print $4 "\t" $1 "\t" $6}'
else
echo -e "${YELLOW}无法检查开放端口(缺少ss/netstat命令)${NC}"
fi
}
# SSH检查
check_ssh() {
print_separator "SSH检查"
# 1. 检查SSH服务状态
echo -e "\n${CYAN}=== SSH服务状态 ===${NC}"
ssh_status=$(systemctl is-active sshd 2>/dev/null || systemctl is-active ssh 2>/dev/null)
if [ "$ssh_status" = "active" ]; then
echo -e "服务状态: ${GREEN}active${NC}"
else
echo -e "服务状态: ${RED}inactive${NC}"
fi
# 2. 检查SSH协议版本
echo -e "\n${CYAN}=== SSH协议版本 ===${NC}"
sshd -T 2>/dev/null | grep -E "^protocol" | awk '{print "SSH协议版本: " $2}'
if grep -q "Protocol 1" /etc/ssh/sshd_config 2>/dev/null; then
echo -e "${RED}⚠ 警告: 检测到不安全的SSH协议版本1${NC}"
fi
# 3. 检查信任主机
echo -e "\n${CYAN}=== 信任主机 ===${NC}"
if [ -f ~/.ssh/known_hosts ]; then
echo -e "已知主机:"
cat ~/.ssh/known_hosts | awk '{print " " $1}'
else
echo -e "无信任主机配置"
fi
# 4. 检查Root登录权限
echo -e "\n${CYAN}=== Root远程登录 ===${NC}"
root_login=$(sshd -T 2>/dev/null | grep -i "permitrootlogin" | awk '{print $2}')
if [ "$root_login" = "yes" ]; then
echo -e "${RED}PermitRootLogin yes (安全风险!)${NC}"
else
echo -e "${GREEN}PermitRootLogin $root_login${NC}"
fi
# 5. 检查密码认证
echo -e "\n${CYAN}=== 密码认证 ===${NC}"
pass_auth=$(sshd -T 2>/dev/null | grep -i "passwordauthentication" | awk '{print $2}')
if [ "$pass_auth" = "yes" ]; then
echo -e "${YELLOW}PasswordAuthentication yes (建议关闭)${NC}"
else
echo -e "${GREEN}PasswordAuthentication $pass_auth${NC}"
fi
# 6. 检查SSH配置文件
echo -e "\n${CYAN}=== SSH配置文件(/etc/ssh/sshd_config) ===${NC}"
if [ -f /etc/ssh/sshd_config ]; then
echo -e "主要配置项:"
grep -E "^PermitRootLogin|^PasswordAuthentication|^Protocol|^Port|^UsePAM|^X11Forwarding|^AllowUsers|^AllowGroups|^DenyUsers|^DenyGroups" /etc/ssh/sshd_config 2>/dev/null | \
while read line; do
key=$(echo "$line" | awk '{print $1}')
value=$(echo "$line" | awk '{print $2}')
case "$key" in
"PermitRootLogin")
[ "$value" = "yes" ] && echo -e "${RED}$line${NC}" || echo -e "${GREEN}$line${NC}"
;;
"PasswordAuthentication")
[ "$value" = "yes" ] && echo -e "${YELLOW}$line${NC}" || echo -e "${GREEN}$line${NC}"
;;
"Protocol")
[ "$value" = "1" ] && echo -e "${RED}$line${NC}" || echo -e "${GREEN}$line${NC}"
;;
*)
echo -e "$line"
;;
esac
done
else
echo -e "${RED}SSH配置文件不存在${NC}"
fi
# 7. 检查SSH监听端口
echo -e "\n${CYAN}=== SSH监听端口 ===${NC}"
ssh_port=$(sshd -T 2>/dev/null | grep "port" | awk '{print $2}' | head -1)
echo -e "SSH端口: $ssh_port"
if [ "$ssh_port" = "22" ]; then
echo -e "${YELLOW}⚠ 警告: 使用默认SSH端口(22)${NC}"
fi
# 8. 检查SSH最近登录
echo -e "\n${CYAN}=== 最近SSH登录 ===${NC}"
last -n 5 | grep -E "ssh|pts" | awk '{print " " $0}'
}
# syslog检查
check_syslog() {
print_separator "syslog检查"
# 1. 检查syslog服务状态
echo -e "\n服务状态:"
syslog_status=$(systemctl is-active rsyslog 2>/dev/null || systemctl is-active syslog 2>/dev/null)
if [ "$syslog_status" = "active" ]; then
echo -e "${GREEN}active${NC}"
else
echo -e "${RED}$syslog_status${NC}"
FAIL_FLAG=1
fi
# 2. 检查syslog配置文件
echo -e "\n/etc/rsyslog.conf"
echo "-----------------"
if [ -f /etc/rsyslog.conf ]; then
# 过滤出主要的日志配置规则
grep -E "^[^#]" /etc/rsyslog.conf 2>/dev/null | \
awk '
/\.info;|authpriv|mail|cron|\.emerg|uucp|local7/ {
# 移除行首空格和注释部分
gsub(/^[ \t]+/, "")
sub(/[ \t]+#.*$/, "")
# 高亮重要配置
if ($0 ~ /authpriv/) {color="\033[1;33m"} # 黄色表示认证日志
else if ($0 ~ /\.emerg/) {color="\033[1;31m"} # 红色表示紧急日志
else color=""
print color $0 "\033[0m"
}
' | column -t -s $'\t'
else
echo -e "${RED}配置文件不存在${NC}"
FAIL_FLAG=1
fi
# 3. 检查日志文件是否存在
echo -e "\n日志文件检查"
echo "-----------"
(
echo -e "日志文件\t\t状态"
grep -E "^[^#]" /etc/rsyslog.conf 2>/dev/null | \
awk '/\// {
# 提取日志文件路径
logfile=$NF
gsub(/^-/, "", logfile) # 处理前面有-的情况
# 检查文件是否存在
if (system("test -f " logfile " 2>/dev/null") == 0) {
status="\033[32m存在\033[0m"
} else {
status="\033[31m缺失\033[0m"
}
printf "%-20s\t%s\n", logfile, status
}'
) | column -t
# 4. 检查日志轮转配置
echo -e "\n日志轮转配置(/etc/logrotate.d/syslog)"
echo "-----------------------------------"
if [ -f /etc/logrotate.d/syslog ]; then
grep -v "^#" /etc/logrotate.d/syslog 2>/dev/null | \
while read line; do
echo -e " $line"
done
else
echo -e " ${YELLOW}未找到日志轮转配置${NC}"
fi
}
# SNMP检查
check_snmp() {
print_separator "SNMP检查"
# 1. 检查SNMP服务状态
echo -e "\n服务状态:"
snmp_status=$(systemctl is-active snmpd 2>/dev/null || echo "unknown")
if [ "$snmp_status" = "active" ]; then
echo -e "${GREEN}active${NC}"
elif [ "$snmp_status" = "unknown" ]; then
echo -e "${YELLOW}unknown${NC}"
else
echo -e "${RED}$snmp_status${NC}"
fi
# 2. 检查SNMP配置文件
echo -e "\n/etc/snmp/snmpd.conf"
echo "---------------------"
if [ -f /etc/snmp/snmpd.conf ]; then
# 显示关键配置项
grep -E "^rocommunity|^rwcommunity|^com2sec|^access" /etc/snmp/snmpd.conf 2>/dev/null | \
while read line; do
# 高亮安全风险配置
if echo "$line" | grep -q "public\|private"; then
echo -e "${RED}$line (安全风险!)${NC}"
else
echo -e "$line"
fi
done
else
echo -e "${YELLOW}配置文件不存在${NC}"
fi
# 3. 检查SNMP监听端口
echo -e "\n监听端口:"
if netstat -tuln | grep -q ":161"; then
echo -e "UDP 161 (SNMP)"
if [ "$snmp_status" = "active" ]; then
echo -e "${GREEN}端口正常监听${NC}"
else
echo -e "${YELLOW}端口监听但服务未运行${NC}"
fi
else
echo -e "${YELLOW}未检测到SNMP端口监听${NC}"
fi
}
# NTP检查
check_ntp() {
print_separator "NTP检查"
# 1. 检查NTP/Chrony服务状态
echo -e "\n服务状态:"
if systemctl is-active chronyd >/dev/null 2>&1; then
echo -e "${GREEN}active (chronyd)${NC}"
ntp_service="chronyd"
elif systemctl is-active ntpd >/dev/null 2>&1; then
echo -e "${GREEN}active (ntpd)${NC}"
ntp_service="ntpd"
else
echo -e "${RED}inactive${NC}"
ntp_service="none"
FAIL_FLAG=1
fi
# 2. 检查时间同步状态
echo -e "\n时间同步状态:"
if [ "$ntp_service" = "chronyd" ]; then
chronyc tracking 2>/dev/null | grep -E "Reference ID|Stratum|System time"
chronyc sources 2>/dev/null | head -5
elif [ "$ntp_service" = "ntpd" ]; then
ntpq -pn 2>/dev/null | head -5
else
echo -e "${YELLOW}未检测到NTP服务${NC}"
fi
# 3. 检查配置文件
echo -e "\n配置文件:"
if [ -f /etc/chrony.conf ]; then
echo -e "/etc/chrony.conf"
echo "----------------"
grep -E "^server|^pool" /etc/chrony.conf 2>/dev/null
elif [ -f /etc/ntp.conf ]; then
echo -e "/etc/ntp.conf"
echo "-------------"
grep -E "^server|^pool" /etc/ntp.conf 2>/dev/null
else
echo -e "${YELLOW}未找到NTP配置文件${NC}"
fi
# 4. 检查时间偏移
echo -e "\n时间偏移:"
if command -v chronyc >/dev/null; then
offset=$(chronyc tracking 2>/dev/null | awk '/System time/ {print $4}')
echo -e "chronyd偏移: ${offset:-未知}"
fi
if command -v ntpdate >/dev/null; then
ntpdate -q pool.ntp.org 2>/dev/null | tail -1
fi
}
# 软件检查
check_software() {
print_separator "软件检查"
# 1. 获取已安装软件列表(RPM系统)
if command -v rpm >/dev/null 2>&1; then
echo -e "\n已安装软件包:"
rpm -qa --queryformat '%-50{NAME}-%{VERSION}-%{RELEASE}.%{ARCH} %{INSTALLTIME:date}\n' 2>/dev/null | \
sort | \
while read -r line; do
# 跳过空行
[ -z "$line" ] && continue
# 提取软件名和架构
pkg=$(echo "$line" | awk '{print $1}')
arch=$(echo "$pkg" | grep -o '\.[^.]*$')
# 高亮特殊软件包
if [[ "$pkg" =~ (shc|wget|net-tools) ]]; then
echo -e "${YELLOW}$line${NC}"
elif [[ "$pkg" =~ (firmware|iwl) ]]; then
echo -e "${BLUE}$line${NC}"
else
echo -e "$line"
fi
done | head -15 # 限制显示数量
# 2. 检查关键软件版本
echo -e "\n关键软件版本:"
check_tools=("wget" "curl" "openssl" "python" "java" "docker")
for tool in "${check_tools[@]}"; do
version=$($tool --version 2>&1 | head -1)
if [ $? -eq 0 ]; then
echo -e "${GREEN}$tool: ${version%% *}${NC}"
else
echo -e "${RED}$tool: 未安装${NC}"
fi
done
# 3. 检查安全更新(修复语法错误)
if command -v yum >/dev/null 2>&1; then
echo -e "\n可用的安全更新:"
yum_output=$(yum list updates --security 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$yum_output" ]; then
echo "$yum_output" | grep -v "Updated Packages" | \
awk 'NR>1 && NF>=2 {print $1"\t"$2}' | while read -r line; do
echo -e "${RED}$line${NC}"
done
else
echo -e "${GREEN}没有可用的安全更新${NC}"
fi
fi
# 4. 检查第三方仓库(修复语法错误)
echo -e "\n第三方仓库:"
if ls /etc/yum.repos.d/* >/dev/null 2>&1; then
grep -lE "epel|ius|rpmforge|remi" /etc/yum.repos.d/* 2>/dev/null | \
while read -r repo; do
echo -e "${YELLOW}$(basename "$repo")${NC}"
done
else
echo -e "未检测到yum仓库文件"
fi
else
echo -e "\n${RED}非RPM系统,无法获取软件包列表${NC}"
fi
}
# 文件检查
check_files() {
print_separator "文件检查"
# 1. 检查最近24小时内被修改过的文件
echo -e "\n############################查看所有被修改过的文件返回最近24小时内的############################"
recent_files=$(find / -type f -mtime -1 2>/dev/null | head -n 10) # 限制显示10个文件
if [ -n "$recent_files" ]; then
echo "$recent_files" | while read -r file; do
# 获取文件详细信息
file_info=$(ls -la "$file" 2>/dev/null)
modify_time=$(date -r "$file" "+%Y-%m-%d %H:%M:%S" 2>/dev/null)
# 高亮关键目录文件
if [[ "$file" =~ /etc/|/root/|/home/ ]]; then
echo -e "${YELLOW}$file_info 修改时间: $modify_time${NC}"
else
echo -e "$file_info 修改时间: $modify_time"
fi
done
else
echo -e "${GREEN}未找到24小时内修改的文件${NC}"
fi
# 2. 检查定时任务文件完整性
echo -e "\n\n############################检查定时文件的完整性############################"
crontab_files=("/etc/crontab" "/etc/cron.d/*" "/var/spool/cron/*")
for crontab_file in ${crontab_files[@]}; do
if [ -f "$crontab_file" ] || [ -d "$crontab_file" ]; then
echo -e "\n文件: ${BLUE}$crontab_file${NC}"
echo "----------------------------------------"
# 显示文件内容,过滤注释和空行
grep -vE '^#|^$' "$crontab_file" 2>/dev/null | while read -r line; do
# 高亮可疑命令
if [[ "$line" =~ (chmod\s+777|rm\s+-rf|wget\s+http|curl\s+-sL) ]]; then
echo -e "${RED}$line${NC}"
else
echo -e "$line"
fi
done
fi
done
# 3. 检查系统关键文件完整性
echo -e "\n\n############################系统关键文件检查############################"
critical_files=(
"/etc/passwd"
"/etc/shadow"
"/etc/group"
"/etc/sudoers"
"/etc/ssh/sshd_config"
)
(
echo -e "文件\t\t\t权限\t所有者\t大小\t修改时间"
for file in "${critical_files[@]}"; do
if [ -f "$file" ]; then
file_perms=$(stat -c "%A" "$file")
file_owner=$(stat -c "%U:%G" "$file")
file_size=$(stat -c "%s" "$file")
file_mtime=$(stat -c "%y" "$file" | cut -d'.' -f1)
# 检查异常权限
if [[ "$file_perms" =~ "rwx" ]] && [[ "$file" != "/etc/shadow" ]]; then
echo -e "${RED}$file\t$file_perms\t$file_owner\t$file_size\t$file_mtime${NC}"
else
echo -e "$file\t$file_perms\t$file_owner\t$file_size\t$file_mtime"
fi
else
echo -e "${YELLOW}$file\t文件不存在${NC}"
fi
done
) | column -t -s $'\t'
}
# 系统命令替换检查
check_command_integrity() {
print_separator "查看系统命令是否被替换"
# 1. 检查常见系统命令目录
common_bin_dirs=("/bin" "/sbin" "/usr/bin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin")
for bin_dir in "${common_bin_dirs[@]}"; do
if [ -d "$bin_dir" ]; then
echo -e "\n目录: ${BLUE}$bin_dir${NC}"
echo "----------------------------------------"
# 获取目录总大小和文件数
dir_size=$(du -sh "$bin_dir" 2>/dev/null | awk '{print $1}')
file_count=$(find "$bin_dir" -type f | wc -l)
echo -e "总大小: $dir_size\t文件数: $file_count"
# 2. 检查链接文件
echo -e "\n链接文件检查:"
(
echo -e "权限\t\t链接目标\t\t\t文件名"
find "$bin_dir" -type l -ls 2>/dev/null | awk '{
# 提取权限、文件名和链接目标
permissions=$3
split($13, parts, "->")
filename=parts[1]
target=parts[2]
# 检查可疑链接
if (target ~ /\.\./ || target ~ /tmp/ || target ~ /dev/) {
color="\033[1;31m"
} else {
color=""
}
printf "%s\t%s\t\t%s%s\033[0m\n", permissions, target, color, filename
}'
) | column -t -s $'\t' | head -10 # 限制显示数量
# 3. 检查文件修改时间
echo -e "\n最近修改的文件:"
find "$bin_dir" -type f -printf "%Tb %Td %Tk:%TM %TY\t%p\n" 2>/dev/null | \
sort -r | head -5 | while read -r line; do
file=$(echo "$line" | awk '{print $5}')
time_info=$(echo "$line" | awk '{$5=""; print $0}')
# 检查最近7天内修改的文件
if find "$file" -mtime -7 2>/dev/null | grep -q .; then
echo -e "${YELLOW}$time_info\t$file${NC}"
else
echo -e "$time_info\t$file"
fi
done
# 4. 检查文件哈希(可选,需要预先保存基准哈希)
if [ -f "/var/log/checksum_$(basename "$bin_dir").log" ]; then
echo -e "\n文件哈希校验:"
current_checksum=$(md5sum "$bin_dir"/* 2>/dev/null | sort)
stored_checksum=$(cat "/var/log/checksum_$(basename "$bin_dir").log")
if diff <(echo "$current_checksum") <(echo "$stored_checksum") >/dev/null; then
echo -e "${GREEN}✓ 文件哈希匹配${NC}"
else
echo -e "${RED}⚠ 文件哈希不匹配${NC}"
diff <(echo "$current_checksum") <(echo "$stored_checksum") | grep "^>" | \
awk '{print " 修改的文件: " $3}'
fi
fi
fi
done
# 5. 检查关键系统命令
echo -e "\n关键系统命令检查:"
critical_commands=("ls" "ps" "netstat" "ss" "find" "top" "ifconfig" "ip" "passwd" "su" "sudo")
(
echo -e "命令\t\t路径\t\t\t\t哈希值"
for cmd in "${critical_commands[@]}"; do
cmd_path=$(which "$cmd" 2>/dev/null)
if [ -n "$cmd_path" ]; then
cmd_hash=$(md5sum "$cmd_path" 2>/dev/null | awk '{print $1}')
# 检查命令是否在标准路径
if [[ "$cmd_path" =~ ^(/bin|/sbin|/usr/bin|/usr/sbin) ]]; then
echo -e "$cmd\t\t$cmd_path\t$cmd_hash"
else
echo -e "${RED}$cmd\t\t$cmd_path\t$cmd_hash (非标准路径)${NC}"
fi
else
echo -e "${YELLOW}$cmd\t\t未找到${NC}"
fi
done
) | column -t -s $'\t'
}
# 总结报告(问题导向版)
show_summary() {
print_separator "巡检问题汇总"
# 初始化问题计数器
high_risk=0
medium_risk=0
low_risk=0
# 1. 高风险管理问题
echo -e "\n${RED}===== 高风险问题 (需立即处理) =====${NC}"
# SSH检查问题
if grep -q "PermitRootLogin yes" /etc/ssh/sshd_config 2>/dev/null; then
echo -e " ✗ SSH允许root登录:${RED}建议禁用root远程登录${NC}"
((high_risk++))
fi
# 密码检查问题
if awk -F: '($2 == "" || $2 == "!") {print $1}' /etc/shadow 2>/dev/null | grep -q .; then
echo -e " ✗ 存在空密码账户:${RED}请立即设置密码${NC}"
((high_risk++))
fi
# 无高风险的默认输出
[ $high_risk -eq 0 ] && echo -e " ${GREEN}✓ 未发现高风险问题${NC}"
# 2. 中风险问题
echo -e "\n${YELLOW}===== 中风险问题 (建议处理) =====${NC}"
# 防火墙检查
if ! systemctl is-active firewalld >/dev/null && ! systemctl is-active iptables >/dev/null; then
echo -e " ⚠ 防火墙未启用:${YELLOW}建议启用防火墙${NC}"
((medium_risk++))
fi
# 密码策略检查
if grep -q "^PASS_MAX_DAYS" /etc/login.defs && [ $(grep "^PASS_MAX_DAYS" /etc/login.defs | awk '{print $2}') -gt 90 ]; then
echo -e " ⚠ 密码有效期过长:${YELLOW}建议设置为90天以下${NC}"
((medium_risk++))
fi
# 无中风险的默认输出
[ $medium_risk -eq 0 ] && echo -e " ${GREEN}✓ 未发现中风险问题${NC}"
# 3. 低风险问题
echo -e "\n${BLUE}===== 低风险问题 (可选处理) =====${NC}"
# 默认SSH端口检查
if ss -tuln | grep -q ":22 "; then
echo -e " ⓘ 使用默认SSH端口:${BLUE}建议修改为非常规端口${NC}"
((low_risk++))
fi
# 无低风险的默认输出
[ $low_risk -eq 0 ] && echo -e " ${GREEN}✓ 未发现低风险问题${NC}"
# 4. 统计信息
echo -e "\n${MAGENTA}===== 问题统计 =====${NC}"
echo -e " 高风险问题: ${RED}$high_risk 个${NC}"
echo -e " 中风险问题: ${YELLOW}$medium_risk 个${NC}"
echo -e " 低风险问题: ${BLUE}$low_risk 个${NC}"
total_problems=$((high_risk + medium_risk + low_risk))
echo -e " 总计发现问题: $total_problems 个"
# 5. 修复建议
if [ $total_problems -gt 0 ]; then
echo -e "\n${CYAN}===== 修复建议 =====${NC}"
[ $high_risk -gt 0 ] && echo -e " • ${RED}优先处理高风险问题${NC}"
[ $medium_risk -gt 0 ] && echo -e " • ${YELLOW}安排处理中风险问题${NC}"
[ $low_risk -gt 0 ] && echo -e " • ${BLUE}酌情处理低风险问题${NC}"
echo -e " • 查看详细报告: ${REPORT_FILE}"
else
echo -e "\n${GREEN}✓ 系统检查未发现任何问题${NC}"
fi
# 6. 报告信息
echo -e "\n${GREEN}===== 报告生成信息 =====${NC}"
echo -e " 生成时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo -e " 主机名称: $(hostname)"
echo -e " 报告路径: ${REPORT_FILE}"
}
# 主函数
main() {
{
echo -e "${BLUE}系统巡检脚本:Version $(date +%Y-%m-%d)${NC}"
check_system_info
check_cpu
check_memory
check_disk
check_raid
check_network
check_listening
check_processes
check_services
check_users
check_logins
check_security
check_ssh
check_syslog
check_cron
check_autostart
check_password
check_sudoers
check_jdk
check_firewall
check_snmp
check_software
check_ntp
check_files
check_command_integrity
show_summary
if [ $FAIL_FLAG -eq 0 ]; then
echo -e "\n${GREEN}===== 巡检完成,未发现严重问题 =====${NC}"
else
echo -e "\n${RED}===== 巡检完成,发现需要关注的问题 =====${NC}"
fi
} | tee -a $REPORT_FILE
echo -e "\n报告已保存至: ${BLUE}$REPORT_FILE${NC}"
}
main
1190

被折叠的 条评论
为什么被折叠?



