在 Shell 算术评估中使用未经净化的数据的安全影响

在 Shell 算术评估中使用未经净化的数据的安全影响

在一个评论到一个最近的问题,Stéphane Chazelas 提到双括号算术存在安全隐患,例如:

x=$((1-$x))

在大多数贝壳上。

我的谷歌技能似乎生锈了,我什么也找不到。双括号算术的安全隐患是什么?

答案1

问题在于,如果 的内容$x尚未清理并且包含可能受到攻击者控制的数据,那么 shell 代码最终可能会在权限升级上下文中使用(例如,由 setuid 调用的脚本)应用程序、sudoers 脚本或用于直接或间接处理离网数据(CGI、DHCP 挂钩...)。

如果:

x='(PATH=2)'

然后:

x=$((1-$x)))

PATH设置为2(很可能受到攻击者控制的相对路径)有副作用。您可以替换PATHLD_LIBRARY_PATHIFS... bash、zsh 或 ksh 中也会发生同样的情况x=$((1-x))(不是 dash 或 yash,它们只接受变量中的数字常量)。

注意:

x=$((1-$x))

$x在某些实现(根据 POSIX 可选)(减量)运算符的 shell 中,对于 的负值将无法正常工作--(与 一样x=-1,这意味着要求 shell 计算1--1算术表达式)。"$((1-x))"没有问题,因为x作为算术评估的一部分(而不是之前)进行了扩展。

bash,zshksh(非dashyash)中,如果x是:

x='a[0$(uname>&2)]'

$((1-$x))然后或的扩展导致执行$((1-x))该命令(对于,需要是一个数组变量,但可以使用例如它)。unamezshapsvar

总之,不应在 shell 的算术表达式中使用未初始化或未清理的外部数据。

$((...))请注意,算术评估可以通过(又名$[...]inbash或)来完成,但也取决于、/ 、、、、、、、内置函数、数组索引和构造zsh中的 shell等)。let[testdeclare/typeset/export...returnbreakcontinueexitprintfprint((..))[[...]]

ksh因为它适用于//中的数组索引,zsh所以bash它也适用于所有以变量名作为参数的内置函数([/ testwith -v, read, unset, export// typeset, / readonlywith , ... )。printprintf-vgetopts

事实上,使用[[...]]或不使用[/内置函数将数字测试运算符的操作数视为算术表达式,这是在or中通常更倾向于使用后者的test原因之一。bashzsh

比较:

$ a='x[1$(uname>&2)]' bash -c '[ "$a" -eq "$b" ]'
bash: line 0: [: x[1$(uname>&2)]: integer expression expected

(安全)与:

$ a='x[1$(uname>&2)]' bash -c '[[ "$a" -eq "$b" ]]'
Linux

uname已被处决)。

(在ksh, 和[都有[[ ... ]]问题)

要检查变量是否包含文字十进制整数,可以使用 POSIXly:

case $var in
  ("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac

请注意,在某些区域设置中[0-9], 和[[:digit:]]的匹配范围超过 0123456789,因此应避免进行任何形式的输入验证/清理。

另请记住,在某些情况下,带有前导零的数字被视为八进制(010有时是 10,有时是 8),并且请注意,上面的检查将允许可能大于您的系统(或您将使用的任何应用程序)支持的最大整数的数字。使用该整数;例如,bash 将 18446744073709551616 视为 0,因为那是 2 64)。因此,您可能需要在上面的 case 语句中添加额外的检查,例如:

(0?* | -0?*)
  echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
  echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;

例子:

$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ bash -c 'read "$x"' < /dev/null
Linux
$ env psvar= bash -c 'unset "$x"'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux

更多阅读:

相关内容