如何防止脚本/命令劫持会话的缓存 sudo 能力?

如何防止脚本/命令劫持会话的缓存 sudo 能力?

如果我运行一个sudo命令,它会要求我输入密码,但是在接下来的几分钟的终端会话中,它会允许我运行sudo命令而不要求我输入密码,因为它会缓存我被允许的信息。

这很方便,而且我发现它相当方便,所以我不想通过每次都要求输入密码而不是缓存来解决这个问题。

但我最近发现一些相当令人担忧的事情,例如如果我创建一个这样的小脚本:

#!/bin/bash

sudo rm -rf /

在我执行任何sudo命令之前,我在终端中以普通用户身份执行它,然后一切正常,并且按预期工作,它会提示我输入sudo密码。但是,如果我要sudo在执行此脚本之前运行命令没有 sudo它会缓存sudo该会话中几分钟内不应要求输入密码的命令,然后即使我没有授予脚本sudo权限,它也不会提示我输入密码,并且脚本将被允许执行sudo它想要的任何命令。

现在我不是那种在不知道脚本内容的情况下执行许多脚本的人,但有时我必须从受信任位置获取的脚本安装东西,但我不确定脚本中是否没有任何不好的东西,所以我希望它不会劫持sudo授予我的终端会话的能力。

所以我的问题是,是否可以让我能够运行sudo命令,它会为我缓存它,但如果我运行一个脚本不是sudo脚本不能劫持该功能吗?我知道我执行脚本基本上与我按照脚本中的顺序执行命令相同,但是有没有办法巧妙地让它以略有不同的方式运行,或者对我sudo运行的脚本进行限制?

但实际上,我没有运行的任何东西都不sudo应该能够运行sudo。包括命令。如果他们只是劫持了缓存的能力,那就是……

我正在运行带有 GNOME 3.18 的 Ubuntu GNOME 15.10。

我对如何做到这一点有一个建议,但我不知道这样做的实用性:我是否可以这样做,当我执行一个命令并开始运行它时,它会将其记录到一个文件中(就像对所有终端命令所做的那样,尽管可能有点太晚了 - 使用该history命令)然后在sudo运行时它会检查我是否在终端中执行了该命令(通过使用我执行时记录的日志),如果没有,则假定这不是我执行的,所以它会提示我输入密码?

答案1

你可以运行

sudo -k

在您运行脚本之前。它将清除缓存的凭据,然后下次sudo将再次询问您的密码。

这是实现您想要做的事情的一种方法(我认为)。

  1. 将您的 sudo 移到其他地方:

    mv /usr/bin/sudo /usr/bin/sudo_real
    
  2. 将以下内容放入usr/bin/sudo

    #!/bin/bash -i
    # Allows 'sudo' to be run with cached credentials from the command line,
    # but clears the cache if run from within a script.
    # Get the last command executed manually from the history
    LAST_COMMAND=`history | tail -n 1 | cut -c 8-`
    
    if [[ "${LAST_COMMAND}" == "sudo "* ]]; then
        # The last command was 'sudo' - i.e. the user ran sudo 
        sudo_real "$@"
    else
        # The last command was NOT sudo - so this sudo was called from within a script.
        # Force the cached credentials to be cleared. 
        sudo_real -k "$@"
    fi
    
  3. 创建新的/usr/bin/sudo可执行文件:

    chmod a+x /usr/bin/sudo
    
  4. sudo通过将其放入以下位置,从 shell 运行 bash 时更新 bash 历史记录的别名~/.bashrc

    alias sudo="history -a;sudo"
    

现在,当您运行它时,sudo ...它会将放入sudo ...bash 历史记录中,并且脚本会找到它并运行sudo_real。但是当另一个脚本运行时sudo,它将不会出现在历史记录中,并且它会调用sudo_real -k

我认为这是非常危险的,我个人宁愿承担风险,或者对我不信任的脚本使用新的 shell :-)

答案2

我对这个问题的立场是这样的:如果你不确定在你的凭据尚未超时的情况下是否可以以 root 权限运行应用程序,那么只需完全禁用超时,将其设置为 0。具体来说,你需要在你的/etc/sudoers文件中进行以下设置:

Defaults    timestamp_timeout=0

手册页定义它如下:

 timestamp_timeout
                   Number of minutes that can elapse before sudo will ask
                   for a passwd again.  The timeout may include a frac‐
                   tional component if minute granularity is insufficient,
                   for example 2.5.  The default is 15.  Set this to 0 to
                   always prompt for a password.  If set to a value less
                   than 0 the user's time stamp will never expire.  This
                   can be used to allow users to create or delete their
                   own time stamps via “sudo -v” and “sudo -k” respec‐
                   tively.

但是,如果你想要谨慎,你可以在.bashrc

sudo_check()
{
  real_path="$( realpath $1 )"
  file "$real_path" | grep -q -i script
  if [ $? -eq 0 ]; then
     grep -q 'sudo' "$real_path"  && \
     { echo '>>> ALERT: Its a script that requests sudo';
       echo '    resetting sudo timestamp';
       echo 'please rerun with sudo appended ';
     }
     sudo -k
  else
     sudo "$@"
  fi

}

此函数将检查脚本是否包含对的调用sudo并提醒您。下面是我在脚本上运行该函数的示例(这是我的登录屏幕背景更换器顺便一提 )

$ sudo_check sergrep/chgreeterbg.sh                            
>>> ALERT: Its a script that requests sudo
    resetting sudo timestamp

答案3

如何区分脚本和可执行二进制命令?

当然,你可以考虑定义一个名为的函数sudo,在运行实际的二进制文件之前进行健全性检查,但是

  • 由于脚本可以有任何名称,那么如果脚本的名称为 会怎么样ls?因此检查类似这样的扩展名.sh不会有帮助
  • 另外,将 shebang 读作脚本的第一行也无济于事,因为脚本可以在没有 shebang 的情况下运行

我认为,如果您对此过于偏执,您可以考虑通过创建别名来完全禁用密码缓存,例如:

alias sudo='sudo -k'

并将其放入你的~/.bashrc

答案4

如果您的版本至少为 1.8.21 sudo,则需要将其设置timestamp_typeppid,而不是默认的tty
默认情况下,sudo 将在每个终端上“缓存凭据”。此设置将sudo仅在调用过程相同时才重用它们。您运行的任何脚本都将具有与您的 shell 不同的 PID,并且将无法使用您的授权。

sudoers具体来说,您的文件中需要包含以下行:
Defaults timestamp_type=ppid

更多详情请参阅手动的

相关内容