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

时间:2019-06-20 14:15:59

标签: 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

1 个答案:

答案 0 :(得分:3)

不要使用黑名单。

数据中明确禁止的内容黑名单只是邀请某人提出其上未存在的漏洞,或混淆其代码以使正则表达式无法与之匹配或查找您的 actual 外壳程序认可的一种奇怪的语法,但黑名单/验证程序所使用的外壳程序则不支持。

不要打那失败的战斗;相反,通过编写绝对安全的代码无论您的数据包含什么内容,都不要在可能被评估和执行为代码的上下文中注入数据。


安全地在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
    

    在所有这些情况下,用户提供的值($1)用于将由Shell解析为代码的上下文中。在所有这些情况下,值都可以运行任意命令。

  • 这始终是安全的:

    grep -e "$1" /var/log/*          ## ALWAYS DO THIS INSTEAD
    

    同样,这始终是安全的。即使$(rm -rf ~)\'$(rm -rf ~\)'中有$1之类的内容,shell也不会将任何内容作为语法进行评估,因此这些值本质上无法解析为代码。

安全地生成Shell命令行

如果被迫使用system()或同等的

  • 这本质上是不安全的:

    system("grep -e \"" + input + "\" /var/log/*")                 /* DO NOT EVER DO THIS */
    system("grep -e '" + input + "' /var/log/*")            /* DO NOT EVER DO THIS EITHER */
    
  • 这本质上是安全的:

    setenv("logs_to_grep", input);           /* IF YOU MUST USE system(), DO THIS INSTEAD */
    system("grep -e \"$logs_to_grep\" /var/log/*")    
    

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

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

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

printf -v args_q '%q ' "$@"
ssh somehost 'bash -s' <<EOF
command_with $args_q
EOF

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

但是更好的选择?不要调用多余的炮弹。

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

# BAD/EVIL/INSECURE
subprocess.Popen('yourscript ' + arg, shell=True)  ## DO NOT EVER DO THIS

# GOOD/SECURE
subprocess.Popen(['yourscript', arg])              ## DO THIS INSTEAD.

不要做其他不安全的事情

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

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

  • xargs -0-与上述find . -type f -exec sh -c 'something_with {}' \;相同的问题,并且具有相同的解决方案:xargs

  • 请勿使用find . -exec sh -c 'for arg; do something_with "$arg"; done' _ {} +eval或将非恒定字符串解析为代码的任何其他内容。同样,这些值在您的数据内都非常好且安全;您根本不应该在代码中使用它们

  • 除了操作系统强制执行的文件名外,不要假设文件名。请勿在脚本中使用source。不要用换行符分隔文件名-而是使用NUL。