最近在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变量本身的任何评估。
但实际上不是:由于-eq,num是按照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[...]检查下标是否存在,因此需要评估表达式。据我所知,这在任何地方都没有很好地记录。
- 从Vidar Holen 的博客中简化和调整而来,我在那里了解到了这一点!↩
- 我询问了我的同事:在 17 名受访者中,16 人认为这段代码没问题,1 人认为它包含潜在漏洞。↩
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。