可以通过该脚本监控 Linux 系统中两个尤为棘手的地方——系统用户 shell 和有潜在危险的文件权限。
一、获得默认的shell审计功能
系统账户用于提供服务或执行特殊任务。一般来说,这类账户需要在 /etc/passwd 文件中有对应的记录,但禁止登录系统(root 账户是一个典型的例外)。
- 防止有人使用这些账户登录的方法是,将其默认 shell 设置为 /bin/false、/usr/sbin/nologin 或 /sbin/nologin。
- 当系统账户的默认 shell 从当前设置更改为 /bin/bash 时,就会出现问题。
- 虽然不良行为者在没有设置密码的情况下无法登录到该账户,但这仍会削弱系统的安全性。
- 因此,账户设置需要进行审计,以纠正不正确的默认 shell。
- 审计这种潜在问题的一种方法是确定有多少账户的默认 shell 被设置为 false 或 nologin,然后定期检查这一数量。如果发现数量减少,则有必要进一步调查。
- 首先,使用
cut
命令获取 /etc/passwd 文件中所有账户的默认 shell :
# 1.对于/etc/passwd 文件,分隔符是冒号(:),账户的默认 shell 位于记录的第 7 个字段。
[root@VM-8-11-centos ~]# cut -d: -f7 /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown
/sbin/halt
/sbin/nologin
...
[root@VM-8-11-centos ~]#
- 通过正则表达式过滤,只需要包含 false 和 nologin 的:
[root@VM-8-11-centos ~]# cut -d: -f7 /etc/passwd |
> grep -E "(false|nologin)"
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
...
[root@VM-8-11-centos ~]#
- 接下来,我们需要
wc
命令获取数量,通过tee
命令写入报告文件,同时希望将这一信息显示给脚本用户:
# 1.系统中共有 21 个账户使用 false 或 nologin 作为默认 shell。
[root@VM-8-11-centos AuditReports]# cut -d: -f7 /etc/passwd |
> grep -E "(false|nologin)" | wc -l |
> tee mydefaultshell.rpt
21
[root@VM-8-11-centos AuditReports]#
[root@VM-8-11-centos AuditReports]# cat mydefaultshell.rpt
21
[root@VM-8-11-centos AuditReports]#
- 由于需要保留多份报告供以后比较,因此可以在报告名中加入日期:
reportDir="/home/jan/scripts/AuditReports"
# 2.使用 date 命令,将格式设置为以连字符分隔(%F)的当前日期。因为审计可能每天执行多次,所以我们还为时间戳添加了额外的时间标识信息(%s):自 1970 年 1 月 1 日以来的秒数。
reportDate="$(date +%F%s)"
accountReport=$reportDir/AccountAudit$reportDate.rpt
cat /etc/passwd | cut -d: -f7 |
grep -E "(nologin|false)" | wc -l |
tee $accountReport
- 为了保护报告,需要设置不可变属性( immutable attribute ),只要对文件设置了该属性,任何人都无法修改或删除此文件(以及一些其他特性)。要设置不可变属性,需要使用
chattr
命令,并且具有超级用户权限:
# 1.设置不可变属性。
[root@VM-8-11-centos AuditReports]# sudo chattr +i mydefaultshell.rpt
[root@VM-8-11-centos AuditReports]#
# 2.无法执行删除操作。
[root@VM-8-11-centos AuditReports]# rm -i mydefaultshell.rpt
rm: remove regular file ‘mydefaultshell.rpt’? y
rm: cannot remove ‘mydefaultshell.rpt’: Operation not permitted
[root@VM-8-11-centos AuditReports]#
# 3.无法执行修改操作。
[root@VM-8-11-centos AuditReports]# echo "Hello" >> mydefaultshell.rpt
-bash: mydefaultshell.rpt: Permission denied
[root@VM-8-11-centos AuditReports]#
# 4.查看文件内容。(未变化)
[root@VM-8-11-centos AuditReports]# cat mydefaultshell.rpt
21
[root@VM-8-11-centos AuditReports]#
- 设置了不可变属性(有时也称作不可变位)之后,任何人都无法删除或修改该文件,哪怕具有超级用户权限也不行。
- 要想查看属性是否设置成功,可以使用
lsattr
命令,并在输出中查找 i。 - 要想移除不可变属性,需要再次使用
chattr
命令(具有超级用户权限),之后文件就能正常修改或删除了:
# 1.查看不可变属性。(输出中有 i 表示设置成功。)
[root@VM-8-11-centos AuditReports]# lsattr mydefaultshell.rpt
----i--------e-- mydefaultshell.rpt
[root@VM-8-11-centos AuditReports]#
# 2.取消不可变属性。
[root@VM-8-11-centos AuditReports]# sudo chattr -i mydefaultshell.rpt
[root@VM-8-11-centos AuditReports]#
# 3.再次查看不可变属性。(输出中没有 i 表示取消成功。)
[root@VM-8-11-centos AuditReports]# lsattr mydefaultshell.rpt
-------------e-- mydefaultshell.rpt
[root@VM-8-11-centos AuditReports]#
# 4.执行修改操作。
[root@VM-8-11-centos AuditReports]# echo "Hello" >> mydefaultshell.rpt
[root@VM-8-11-centos AuditReports]#
# 5.修改成功。
[root@VM-8-11-centos AuditReports]# cat mydefaultshell.rpt
21
Hello
[root@VM-8-11-centos AuditReports]#
# 6.删除成功。
[root@VM-8-11-centos AuditReports]# rm -i mydefaultshell.rpt
rm: remove regular file ‘mydefaultshell.rpt’? y
[root@VM-8-11-centos AuditReports]#
- 我们的审计报告现在已经得到了保护,只剩下最后一个问题:将当前报告与上一份报告进行比较。
ls
命令会按照从新到旧的顺序在单列中列出文件:
# 1.创建两份报告。
[root@VM-8-11-centos AuditReports]# reportDate="$(date +%F%s)"
[root@VM-8-11-centos AuditReports]# touch AccountAudit$reportDate.rpt
[root@VM-8-11-centos AuditReports]#
[root@VM-8-11-centos AuditReports]# reportDate="$(date +%F%s)"
[root@VM-8-11-centos AuditReports]# touch AccountAudit$reportDate.rpt
[root@VM-8-11-centos AuditReports]#
# 2.从新到旧排序。
[root@VM-8-11-centos AuditReports]# ls -1t AccountAudit*.rpt
AccountAudit2023-07-171689576240.rpt
AccountAudit2023-07-171689576199.rpt
[root@VM-8-11-centos AuditReports]#
- 之所以要以单列格式列出文件,是因为我们可以使用
sed
来获取次旧( the second oldest )报告的文件名进行比较:
prevReport="$(ls -1t $reportDir/AccountAudit*.rpt |
sed -n '2p')"
# 如果没有次旧报告则提示。
if [ -z $prevReport ]; then
echo
echo "No previous false/nologin report exists to compare."
else
echo
echo "Previous report's false/nologin shells: "
cat $prevReport
fi
#
- 现在,所有的默认 shell 审计功能都已经完成,接下来可以看看权限审计功能的实现了。
二、权限审计功能
SUID( set user ID )和 SGID( set group ID )是两种很方便的权限设置,被 Linux 虚拟目录系统中的多个程序使用。然而,如果这些权限被无意甚至恶意地设置在程序上,导致其在不同的权限下运行,则会引发安全问题。因此,有必要在系统中对这两种潜在的“危险”权限进行审计,确保它们只被设置在该设置的地方。
- 要找出具有这两种权限的文件和目录,需要使用
find
命令:
# 1.查找 SUID 和 SGID 两种权限的文本和目录。
# 超级用户权限,已根目录(/)为起点。
# -perm(permissions)选项可以使用八进制值指定要查找的具体权限。
# -perm 的值是/6000。八进制值 6 表示 find 要查找的权限是 SUID 和 SGID。
# 为了保持显示整洁,我们将错误消息(2)直接丢弃(/dev/null)。
[root@VM-8-11-centos AuditReports]# sudo find / -perm /6000 2>/dev/null
-
注意事项:旧版本的
find
命令使用加号(+)表示忽略某些权限。如果你用的 Linux 版本比较旧,则可能需要把正斜线换成加号。 -
可以将
find
命令中的 STDOUT 重定向到文件中,以便以后轻松查看。保存报告,随后与权限审计进行比较:
reportDir="/home/christine/scripts/AuditReports"
reportDate="$(date +%F%s)"
permReport=$reportDir/PermissionAudit$reportDate.rpt
#
sudo find / -perm /6000 >$permReport 2>/dev/null
-
权限审计报告现在已保存,我们可以将该报告的早期版本与当前版本进行比较,通知脚本用户两者之间的差异。
-
文件权限发生变化则表明,要么安装的新软件有此需求,要么文件被错误(或恶意)地设置为这些权限。
-
为了进行比较,可以使用
diff
命令。此命令可以比较文件,并将两者之间的差异输出到 STDOUT。 -
注意事项:
diff
命令只会逐行对文件进行比较。- 因此,
diff
会比较两份报告的第一行,然后是第二行、第三行,以此类推。 - 如果由于要安装软件,添加了一个或一批新文件,而这些文件需要 SUID 权限或 SGID 权限,那么在下一次审计时,
diff
就会显示大量的差异。 - 为了解决这个潜在的问题,可以在
diff
命令中使用 -q 选项或 –brief 选项,只显示消息,说明这两份报告存在不同。
-
在进行比对之前,还需要核实另一份报告是否存在。相关代码如下:
prevReport="$(ls -1t $reportDir/PermissionAudit*.rpt |
sed -n '2p')"
#
if [ -z $prevReport ]; then
echo
echo "No previous permission report exists to compare."
else
echo
echo "Differences between this report and the last: "
#
differences=$(diff $permReport $prevReport)
#
if [ -z "$differences" ]; then
echo "No differences exist."
else
echo $differences
fi
fi
- 注意事项:不仅要检查另一份报告,还要查看两份报告之间是否确实存在差异。如果不存在差异,则仅显示 No differences exist。
三、创建脚本
现在,我们已经实现了审计脚本所有的主要功能,可以将它们组合在一起了。
- 对于这个 bash shell 脚本,我们打算使用
getopts
并提供两个选项:-A 选项仅执行账户审计,-p 选项仅执行权限审计。 - 虽然可以通过组合这两个选项(-Ap)来执行两项审计,但如果没有指定任何选项,则也可以实现相同的效果,这算是为用户提供了一定的灵活性。
- 因而也可以通过
cron
或anacron
更轻松地将该脚本引入自动化环境。 - 下面是完整的 Audit_System.sh 脚本:
#!/bin/bash
#
#################### 初始化变量 ####################
runAccountAudit="false"
runPermAudit="false"
#
reportDir="/home/jan/scripts/AuditReports"
#
#################### 获取选项 ####################
#
while getopts :Ap opt; do
case "$opt" in
A) runAccountAudit="true" ;;
p) runPermAudit="true" ;;
*)
echo "Not a valid option."
echo "Valid options are: -A, -p, or -Ap"
exit
;;
esac
done
#
# 如果没有选项,则将标记变量设置为true。
#
if [ $OPTIND -eq 1 ]; then
runAccountAudit="true"
runPermAudit="true"
fi
#
#################### 执行账户审计 ####################
#
if [ $runAccountAudit = "true" ]; then
echo
echo "****** Account Audit *****"
echo
#
# 确定当前的 false/nologin shell 计数。
#
echo "Number of current false/nologin shells: "
#
reportDate="$(date +%F%s)"
accountReport=$reportDir/AccountAudit$reportDate.rpt
#
# 创建当前报表。
cat /etc/passwd | cut -d: -f7 |
grep -E "(nologin|false)" | wc -l |
tee $accountReport
#
# 更改报告的属性。
sudo chattr +i $accountReport
#
# 显示过去的 false/nologin shell 计数。
#
prevReport="$(ls -1t $reportDir/AccountAudit*.rpt |
sed -n '2p')"
if [ -z $prevReport ]; then
echo
echo "No previous false/nologin report exists to compare."
else
echo
echo "Previous report's false/nologin shells: "
cat $prevReport
fi
fi
#
#################### 权限审计 ####################
#
if [ $runPermAudit = "true" ]; then
echo
echo "****** SUID/SGID Audit *****"
echo
reportDate="$(date +%F%s)"
permReport=$reportDir/PermissionAudit$reportDate.rpt
#
# 创建当前报表。
echo "Creating report. This may take a while..."
sudo find / -perm /6000 >$permReport 2>/dev/null
#
# 更改报告的属性。
sudo chattr +i $permReport
#
# 与次旧权限报告进行比较。
#
prevReport="$(ls -1t $reportDir/PermissionAudit*.rpt |
sed -n '2p')"
#
if [ -z $prevReport ]; then
echo
echo "No previous permission report exists to compare."
else
echo
echo "Differences between this report and the last: "
#
differences=$(diff $permReport $prevReport)
#
if [ -z "$differences" ]; then
echo "No differences exist."
else
echo $differences
fi
fi
fi
#
exit
四、运行脚本
- 在运行该脚本之前,需要先创建审计报告目录。目录中要保存审计报告,在选择目录位置时一定要谨慎:
[root@VM-8-11-centos scripts]# mkdir AuditReports
[root@VM-8-11-centos scripts]#
[root@VM-8-11-centos scripts]# ls AuditReports/
[root@VM-8-11-centos scripts]#
- 审计报告目录创建好之后,就可以启动脚本了。先使用 -A 选项执行账户默认 shell 审计:
# 1.赋予执行权限。
[root@VM-8-11-centos scripts]# chmod u+x Audit_System.sh
[root@VM-8-11-centos scripts]#
# 2.执行脚本。(-A 选项仅执行账户审计。)
# 注意,系统中共有 21 个账户使用 false 或 nologin 作为默认 shell。另外,由于还没有其他的账户审计报告,因此脚本提醒我们没有可以进行比较的报告。
[root@VM-8-11-centos scripts]# ./Audit_System.sh -A
****** Account Audit *****
Number of current false/nologin shells:
21
No previous false/nologin report exists to compare.
[root@VM-8-11-centos scripts]#
- 再用 -p 选项试试权限审计功能:
# 1.执行脚本。(-p 选项仅执行权限审计。)
[root@VM-8-11-centos scripts]# ./Audit_System.sh -p
****** SUID/SGID Audit *****
Creating report. This may take a while...
No previous permission report exists to compare.
[root@VM-8-11-centos scripts]#
# 2.一切正常。AuditReports 目录中现在已经有了两份审计报告。
[root@VM-8-11-centos scripts]# ls -1 AuditReports/
AccountAudit2023-07-181689664305.rpt
PermissionAudit2023-07-181689664406.rpt
[root@VM-8-11-centos scripts]#
- 现在,让我们添加一个具有 SUID 权限的伪造文件,看看脚本是否能发现。这次也使用两个选项运行脚本(执行两项审计):
# 1.创建伪造文件。
[root@VM-8-11-centos scripts]# touch sneakyFile.exe
[root@VM-8-11-centos scripts]#
# 2.设置 SUID 权限。
[root@VM-8-11-centos scripts]# chmod u+xs sneakyFile.exe
[root@VM-8-11-centos scripts]#
# 3.执行脚本。(两项审计不仅都执行了,而且权限审计还发现了 sneakyFile.exe 的 SUID 权限。)
[root@VM-8-11-centos scripts]# ./Audit_System.sh -Ap
****** Account Audit *****
Number of current false/nologin shells:
21
Previous report's false/nologin shells:
21
****** SUID/SGID Audit *****
Creating report. This may take a while...
Differences between this report and the last:
1d0 < /home/jan/scripts/sneakyFile.exe
[root@VM-8-11-centos scripts]#
-
脚本没有问题,可以开始考虑如何改进了。下面是一些参考建议:
- 添加额外的审计功能,比如有关新增账户或登录失败的报告。
- 限制保存在 AuditReports 目录中的报告数量。
- 使用校验和(详见
man
SHA512sum)提高安全性,确保报告不会被篡改。
-
注意事项:
- 虽然这个脚本对审计工作很方便,但不要把它当作入侵检测系统( intrusion detection system,IDS)。
- IDS 可以监视网络和/或系统中运行的应用程序,寻找可疑行为。
- IDS 提供了各种功能,比如阻止攻击和报告发现的潜在恶意行为。
- 如果担心意图不轨人员破坏系统,那么 IDS(比如 Snort、DenyHosts 和 Fail2ban)是你的最佳选择。
五、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。