bash 中一些令人惊讶的代码执行源

最近在bash(可能在其他 shell 中也有)中遇到了两个令人惊讶的代码执行源。

在历史背景下,这些可能不是太严重的问题,但在 CI 系统中,一切都是 shell 和 YAML 的混乱组合,它们可能是有用的执行原语。

编辑 2024 - 11 - 22:Wooledge Bash 指南中的Bash 陷阱页面包含了这些示例以及其他令人惊讶的评估源。

源 1:算术表达式(又名“白领 eval”)

撇开主要问题不谈,你认为这段bash代码1能运行任意代码吗?

function guess() {
  num="${1}"
  if [[ "${num}" -eq 42 ]]
  then
    echo "Correct"
  else
    echo "Wrong"
  fi
}

大多数人(包括有经验的 shell 程序员2)说“不能”:他们意识到如果是$num而不是"${num}",可能会有一个展开错误,但双引号应该能坚决防止num变量本身的任何评估。

但实际上不是:由于-eqnum是按照bash的算术评估规则处理的,这意味着以下代码有效:

$ guess 'a[$(cat /etc/passwd > /tmp/pwned)] + 42'
Correct
$ cat /tmp/pwned

注意单引号:$(cat /etc/passwd > ~/pwned)不是作为guess的参数急切地执行,而是作为[[-eq评估的一部分执行。

与下面的情况不同,这似乎不适用于[test

源 2:test -v

在与算术表达式相同的条件下(需要使用内置的,而不是标准的二进制文件),test -v var也存在相同的令人惊讶的代码执行源:

$ [[ -v 'x[$(cat /etc/passwd > /tmp/pwned)]' ]]
$ cat /tmp/pwned

只要使用它们的内置变体而不是外部二进制变体,这也适用于[test。当然,/usr/bin/[/usr/bin/test不起作用,因为它们无法访问启动它们的 shell 的上下文。

我不确定为什么会是这样,因为-v var被记录为测试var是否已设置,并且不需要评估下标来确定这一点。

编辑 2024 - 11 - 22:许多人指出-v var[...]检查下标是否存在,因此需要评估表达式。据我所知,这在任何地方都没有很好地记录。

  1. Vidar Holen 的博客中简化和调整而来,我在那里了解到了这一点!
  2. 我询问了我的同事:在 17 名受访者中,16 人认为这段代码没问题,1 人认为它包含潜在漏洞。
阅读 12
0 条评论