在Linux中检查用户sudo访问的4种简单方法
如何检查普通用户是否具有sudo访问权限?
是否有可能知道用户是否具有使用脚本的sudo访问权限?
如果我尝试使用或者验证sudo特权,脚本会提示我们输入用户密码,是否可以在没有密码提示的情况下完成操作?
前几天我在写一个脚本,要求普通用户使用sudo访问权限来执行某些操作。
但是后来我意识到普通用户没有权限读取" sudoers"文件,因为默认情况下它只能由root用户读取
# ls -l /etc/sudoers -r--r----- 1 root root 4367 May 11 11:14 /etc/sudoers
因此,这意味着我们不能由普通用户使用grep,因为它会使Permission被拒绝
[hynman@client root]$grep hynman /etc/sudoers grep: /etc/sudoers: Permission denied
提示:
在继续之前,请确保我们验证用户的组成员身份。
有时,用户可能属于某个admin或者wheel组的一部分,默认情况下,该用户会为用户提供各种sudo特权,即使sudoer可能不包含该用户的任何条目。
例如,在这种情况下,hynman用户是wheel组的一部分,因此默认情况下,他将获得所有适用于root用户的sudo特权。
[root@client ~]# id hynman uid=1001(hynman) gid=1001(hynman) groups=1001(hynman),10(wheel)
因此,要将其视为普通用户,我们必须从轮组中删除该用户。
以普通用户身份检查sudo访问
我们可以使用两种方法来检查脚本内甚至没有脚本的sudo访问。
在本教程中,将介绍我所知道的内容,我们可以使用注释部分将更多内容添加到此列表中。
我们将分析每种方法的优点和缺点,以便我们根据需要选择最合适的一种。
方法1:使用sudo -l或者--list
按照手册页,sudo可以与-l或者--list一起使用,以获取任何特定用户的允许和禁止命令的列表。
语法为:
sudo -l [-AknS] [-a type] [-g group] [-h host] [-p prompt] [-U user] [-u user] [command]
如果我们使用不带任何参数的sudo --list,它将为执行sudo命令的用户打印允许和禁止的命令列表。
# sudo --list <Output trimmed> User root Jan run the following commands on client: (ALL) ALL
类似地,为了验证普通用户,例如,我有一个用户hynman
# sudo -l -U hynman <Output trimmed> User hynman Jan run the following commands on client: (ALL) NOPASSWD: /bin/chmod, !/usr/bin/passwd
因此,用户hynman
被允许使用chmod
,并且被禁止将passwd
与sudo
一起使用。
或者,我们可以以普通用户身份运行它:
[hynman@client ~]$sudo -l <Output trimmed> User hynman Jan run the following commands on client: (ALL) NOPASSWD: /bin/chmod, !/usr/bin/passwd
要获得用户允许/禁止的命令的更详细的输出,可以多次添加-l
[amit@client ~]$sudo -ll Sudoers entry: RunAsUsers: ALL Options: !authenticate Commands: /bin/chown
我们还可以搜索确切的命令,以确保用户是否允许提供的命令
[hynman@client ~]$sudo --list chmod /bin/chmod
因此,我们知道用户可以使用smod来使用chmod命令,类似地,我们尝试检查其他命令:
[hynman@client ~]$sudo --list passwd [hynman@client ~]$echo $? 1
这里的退出状态为非零,因此我们知道用户hynman
没有sudo
访问权限以使用passwd
命令
如果用户" hynman"没有sudo特权,则最终将出现密码提示。
证明密码后,我们将获得以下内容:
[hynman@client ~]$sudo -l [sudo] password for hynman: Sorry, user hynman Jan not run sudo on client.
使用sudo --list的缺点是,第一次执行此命令时,会提示我们输入密码。
[hynman@client ~]$sudo -l -U hynman We trust you have received the usual lecture from the local System Administrator. It usually boils down to these three things: #1) Respect the privacy of others. #2) Think before you type. #3) With great power comes great responsibility. [sudo] password for hynman:
尽管我们可以使用一种变通方法,但可以在第一次会话中以root用户身份执行sudo --list -U <user>,因为第一次执行是使用超级用户并在下次执行,因此不会提示输入密码从现在起,我们甚至可以以普通用户的身份对sudo使用--list来检查sudo访问,而无需任何密码提示
优点
获取允许/禁止的单个命令的完整列表
在" sudoers"列表中获取允许/禁止的命令的详细输出
易于使用,并且不依赖于任何其他命令来执行
缺点
- 这不是脚本编写的理想解决方案,因为如果用户没有sudo访问权限,我们可能会提示输入密码
方法2:使用sudo -v或者--validate
sudo -v或者sudo --validate将更新用户的缓存凭据,并在必要时对用户进行身份验证。
这是检查sudo访问的另一种简单方法,但这可能不会给我们太多细节,如使用sudo --list所示。
如果用户具有sudo访问权限,则此命令将返回零退出状态
[amit@client ~]$sudo --validate [amit@client ~]$echo $? 0
因此,我们知道用户amit
具有sudo访问权限,但他不知道哪个命令对他来说是允许/禁止的。
如果用户没有sudo访问权限,即/etc/sudoers
中没有该用户的条目,则此命令将返回Sorry,用户XXX可能不会在客户端上运行sudo。
[hynman@client ~]$sudo --validate Sorry, user hynman Jan not run sudo on client.
优点
使用方便
如果只需要检查
/etc/sudoers
中用户的存在,该选项将很有用。可根据需要与脚本一起使用
缺点
- 我们没有获得有关单个用户允许/禁止的命令列表的信息
方法3:将sudo与超时一起使用
如果我们只是尝试以普通用户身份对任何命令使用sudo,则缺点是密码提示(假设用户没有sudo访问权限)。
如果用户具有带有NOPASSWD参数的所提供命令的sudo访问权限,那么根本没有问题。
但是在脚本中,我们必须处理正面和负面的情况。
因此,我们还必须处理一种可能的情况,即脚本可能会阻塞,等待使用sudo的用户密码提示。
那么我们该如何处理呢?
超时以重用在bash中,我们有一个timeout实用程序,该实用程序用于杀死卡住的进程,此外,如果出于某种原因超时也被卡住,超时也可以用于杀死自己。
因此,假设用户" hynman"所期望的,他具有使用" chmod"命令的sudo特权,并且尝试从脚本中使用" chmod"
[hynman@client ~]$sudo chmod --help [sudo] password for hynman:
该脚本暂停,等待用户输入。
因此,我们在此命令中添加了" timeout",以监视执行时间,我也添加了时间
[hynman@client ~]$time timeout 2 sudo chmod --help [sudo] password for hynman: real 0m2.011s user 0m0.015s sys 0m0.009s [hynman@client ~]$echo $? 124
因此,在等待2秒钟后,按预期,sudo提示被杀死了。
如果命令超时,并且未设置--preserve-status,则退出并显示状态124. 我们可以使用--preserve-status以命令的退出状态退出
示例脚本
因此我们可以在脚本中使用它,并将输出发送到/dev/null
或者任何日志文件,以避免控制台上出现任何不需要的消息。
我不得不将-k
与timeout
结合使用,因为我发现超时无限期地停留在shell脚本中。
#!/bin/bash timeout -k 2 2 bash -c "sudo chmod --help" >&/dev/null 2>&1 if [ $? -eq 0 ];then echo "yay, user `id -Gn` has sudo access" else echo "sorry, user `id -Gn` has no sudo access" fi
如果执行此脚本,则输出
[hynman@client ~]$/tmp/script.sh /tmp/script.sh: line 3: 2299 Killed timeout -k 2 2 bash -c "sudo chmod --help" &> /dev/null 2>&1 sorry, user hynman has no sudo access
它可以工作,但显然输出效果不好,所以让我们通过将输出发送到/dev/null
来解决此问题。
#!/bin/bash `timeout -k 2 2 bash -c "sudo /bin/chmod --help" >&/dev/null 2>&1` >/dev/null 2>&1 if [ $? -eq 0 ];then echo "yay, user `id -Gn` has sudo access" else echo "sorry, user `id -Gn` has no sudo access" fi
现在我们执行以下脚本:
[hynman@client ~]$/tmp/script.sh sorry, user hynman has no sudo access
因此,现在我们可以在控制台上使用更干净的输出检查sudo访问。
我们还可以根据执行情况分配变量,然后在脚本中使用该变量。
#!/bin/bash has_sudo_access="" `timeout -k 2 2 bash -c "sudo /bin/chmod --help" >&/dev/null 2>&1` >/dev/null 2>&1 if [ $? -eq 0 ];then has_sudo_access="YES" else has_sudo_access="NO" fi echo "Does user `id -Gn` has sudo access?: $has_sudo_access"
现在,假设我已经为/bin/chmod
为用户hynman
添加了sudo访问权限,让我们执行以下脚本:
[hynman@client ~]$/tmp/script.sh Does user hynman has sudo access?: YES
优点
可以在脚本中使用,以检查Linux中普通用户的sudo访问权限
可以根据条件匹配返回用户定义的退出状态或者变量
缺点
该解决方案不是很健壮,就像没有使用连字符(-)来完成切换用户一样,此命令可能会失败,因为找不到正确的
PATH
变量如果没有为命令使用确切的路径,例如其中/bin/chmod,如果我只是使用chmod,那么将不会给出正确的退出状态。
因此,该命令必须与sudoers
列表中的内容匹配与
timeout
实用程序的依赖关系,因此timeout
也必须安装在服务器上。
方法4:与-S或者--stdin一起使用sudo
我们可以将sudo
与--stdin
或者-S
一起使用,以将提示写入标准错误,并从标准输入中读取密码,而无需使用终端设备。
密码后必须带有换行符。
说明:
仅当安全不是首要考虑因素时,才应使用此方法,因为密码将公开可见。
我们可以选择将脚本转换为二进制格式,因此没有人一次可以读取脚本的内容。
示例脚本
例如,在此示例脚本中,我为用户hynman提供密码以检查sudo访问
#!/bin/bash has_sudo_access="" printf "mypassword\n" | sudo -S /bin/chmod --help >/dev/null 2>&1 if [ $? -eq 0 ];then has_sudo_access="YES" else has_sudo_access="NO" fi echo "Does user `id -Gn` has sudo access?: $has_sudo_access"
如果用户具有执行"/bin/chmod"的" sudo"访问权限,则输出为:
Does user hynman has sudo access?: YES
否则我们将得到:
Does user hynman has sudo access?: NO
优点
轻松检查单个命令的sudo访问权限的简单解决方案
可以轻松地在脚本中使用
缺点
- 由于必须在脚本内以纯文本格式提供用户密码,因此对安全性不利。
尽管我们可以使用第三方工具来加密脚本或者将其转换为二进制格式,但没有人可以读取脚本内容。