Linux bash shell 注入命令的可能列表是什么?

Sri*_*uni 0 linux bash shell code-injection

我们正在编写一个接收参数的 Linux bash shell 脚本。当脚本接收到可能的 shell 注入命令作为参数时,我们希望它失败。我在下面使用正则表达式添加了一些命令。有人可以给我所有此类命令的可能列表,以便我们可以避免威胁

invalid_format="(^.*[;&|].*$)|(\brmdir\b)|(\bls\b)|(rm\s-)|(\bping\b)"

if [[ $LOCAL_DIR =~ $invalid_format ]]; then

echo "Error! LOCAL_DIR cannot contain command chaining characters like ; && || or possible shell injection commands"

exit 1
Run Code Online (Sandbox Code Playgroud)

Cha*_*ffy 8

不要使用黑名单。

数据中明确禁止的内容黑名单只是邀请某人提出不存在的漏洞,或者混淆他们的代码以使正则表达式无法匹配它,或者找到奇怪的语法受到您实际shell 的认可,而不是为黑名单/验证器编写的那个 shell。

不要打那场失败的战斗;相反,编写安全的代码,无论您的数据包含什么内容,永远不要将数据注入可以作为代码评估和执行的上下文中。


在 Shell 脚本中安全地使用参数

  • 这本质上是不安全的:

    eval "grep -e \"$1\" /var/log/*"         ## DO NOT EVER DO THIS
    eval "grep -e '$1' /var/log/*"           ## DO NOT EVER DO THIS EITHER
    sh -c "grep -e \"$1\" /var/log/*"        ## DO NOT EVER DO THIS EITHER
    sh -c "grep -e '$1' /var/log/*"          ## DO NOT EVER DO THIS EITHER
    ssh somehost "grep -e \"$1\" /var/log/*" ## DO NOT EVER DO THIS EITHER
    ssh somehost "grep -e '$1' /var/log/*"   ## DO NOT EVER DO THIS EITHER
    
    Run Code Online (Sandbox Code Playgroud)

    在所有这些情况下,用户提供的值 ( $1) 将用于外壳程序将其解析为代码的上下文中。在所有这些情况下,一个值因此可以运行任意命令。

  • 这总是安全的:

    grep -e "$1" /var/log/*          ## ALWAYS DO THIS INSTEAD
    
    Run Code Online (Sandbox Code Playgroud)

    再说一次,这总是安全的。即使$(rm -rf ~)\'$(rm -rf ~\)'$1的里面有类似的东西,shell 也不会将任何内容评估为语法,因此这些值本质上无法被解析为代码。

安全地生成 Shell 命令行

如果被迫使用system()或某些等效

  • 这本质上是不安全的:

    eval "grep -e \"$1\" /var/log/*"         ## DO NOT EVER DO THIS
    eval "grep -e '$1' /var/log/*"           ## DO NOT EVER DO THIS EITHER
    sh -c "grep -e \"$1\" /var/log/*"        ## DO NOT EVER DO THIS EITHER
    sh -c "grep -e '$1' /var/log/*"          ## DO NOT EVER DO THIS EITHER
    ssh somehost "grep -e \"$1\" /var/log/*" ## DO NOT EVER DO THIS EITHER
    ssh somehost "grep -e '$1' /var/log/*"   ## DO NOT EVER DO THIS EITHER
    
    Run Code Online (Sandbox Code Playgroud)
  • 这本质上是安全的:

    grep -e "$1" /var/log/*          ## ALWAYS DO THIS INSTEAD
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,我们根本没有将值放在传递给 shell 的字符串中,而是将其带外传递给环境变量(使用小写名称,因此它不能覆盖任何对操作系统和支持工具具有安全敏感意义的环境变量)。

从另一个 Shell 脚本生成安全命令行

假设您需要通过 SSH 使用不受信任的输入运行命令。printf %q可以帮助:

printf -v args_q '%q ' "$@"
ssh somehost 'bash -s' <<EOF
command_with $args_q
EOF
Run Code Online (Sandbox Code Playgroud)

为什么bash -s?为确保您args_str被 bash 解析,asprintf %q不保证 POSIX 安全输出。

但更好的选择?不要调用额外的 Shell。

不要使用system()或 任何调用sh -c,而是使用直接使用execve()系统调用来调用脚本的语言级工具。例如,在 Python 中:

system("grep -e \"" + input + "\" /var/log/*")                 /* DO NOT EVER DO THIS */
system("grep -e '" + input + "' /var/log/*")            /* DO NOT EVER DO THIS EITHER */
Run Code Online (Sandbox Code Playgroud)

不要做其他不安全的事情

  • xargs -I{} sh -c 'something_with {}'-- 因为您的占位符 ,{}替换为sh作为代码解析的值,所以它被解析为代码,而不是数据。不要那样做。

    相反,将您的数据带外传递:(xargs -d $'\n' sh -c 'for arg; do something_with "$arg"; done' _如果您的数据本质上无法包含换行符;如果您不能证明这是真的,请使用 NUL 分隔符xargs -0)。

  • find . -type f -exec sh -c 'something_with {}' \;-- 与xargs上述相同的问题,具有相同的解决方案:find . -exec sh -c 'for arg; do something_with "$arg"; done' _ {} +

  • 不要使用eval, or source, 或其他任何将非常量字符串解析为代码的东西。同样,这些值在您的数据中都非常好且安全;你根本不应该在你的代码中使用它们。

  • 不要对文件名进行假设,除非您的操作系统强制执行。不要ls在脚本中使用。不要用换行符分隔文件名——改用 NUL。

  • 写得真好! (2认同)