BASH 和回车行为

BASH 和回车行为

我有一个简单的问题。
bash(我使用的是 4.4.11)不显示以 plain 分隔/结尾的行/文本是否正常\r

看到这种行为我有点惊讶:

$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george

但“你好”文本仍然存在,不知何故“隐藏”:

$ echo "$a" |od -w32 -t x1c
0000000  68  65  6c  6c  6f  0d  61  67  61  69  6e  0d  67  65  6f  72  67  65  0d  0a
          h   e   l   l   o  \r   a   g   a   i   n  \r   g   e   o   r   g   e  \r  \n

只要我们只玩 bash 就可以了……但这是否存在潜在的安全风险?如果变量“a”的内容来自外部世界并包含“错误命令”而不仅仅是“hello”怎么办?

另一个测试,这次有点不安全:

$ a=$(printf "ls;\rGeorge\n")
$ echo "$a"
George
$ eval "$a"
0                   awkprof.out       event-tester.log  helloworld.c      oneshot.sh         rightclick-tester.py  tmp                    uinput-simple.py
<directory listing appears with an error message at the end for command George>

想象一下隐藏rm而不是隐藏ls

使用 echo -e 时的行为相同:

$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George

难道是我做错了什么吗……?

答案1

echo "$a"打印“hello”,然后返回到行的开头(这就是所做\r的),打印“again”,再次返回,打印“george”,再次返回,然后转到下一行(\n)。这一切都很正常,但正如切普纳指出,它与 Bash: 没有任何关系,\r并且\n由终端解释,而不是由 Bash 解释(这就是为什么当您将命令通过管道传输到 时会获得完整输出od)。

你可以更好地看到这一点

$ a=$(printf "hellooooo\r  again,\rgeorge\r\n")
$ echo "$a"

因为这将留下被覆盖文本的结尾:

georgen,o

不过,您不能真正使用它来隐藏命令,只能使用它们的输出(并且只有当您确定用足够的字符覆盖时),除非eval按照您显示的方式使用(但eval通常不建议使用)。更危险的伎俩是使用 CSS 屏蔽命令旨在从网站复制和粘贴。

答案2

在 Unix 世界中,一个回车(通常\r在编程语言中编码)是一个不起眼的控制字符。您可以在一行文本中包含回车符,就像除换行符之外的任何其他字符一样(也称为新队),它标志着一行的结束。

特别是,在 bash 脚本中,回车符是普通的单词组成字符,就像字母和数字一样。回车的任何特殊效果都来自终端,而不是来自 shell。

回车符是控制字符。当您将其打印到终端时,而不是显示字形,终端执行一些特殊效果。对于回车,特殊效果是将光标移动到当前行的开头。因此,如果打印中间包含回车的行,则效果是后半部分写在前半部分之上。

其他几个控制字符具有特殊效果:退格字符将光标向左移动一个位置。响铃字符使终端发出声音或以其他方式吸引用户的注意力。转义字符开始转义序列可以产生各种特殊效果。

如果显示不受信任的输出,则需要擦除或转义控制字符。不仅是回车符,还有其他几个字符,特别是转义符,都会造成各种不好的影响。看“整理”文件会构成潜在的安全风险吗?如何避免终端中的转义序列攻击?了解有关该主题的更多信息。

答案3

printf您可以使用具有格式的函数查看 bash 变量中的回车符%q

$ TESTVAR="$(printf ' Version: 1 \r Build: 20180712 \r Test: 1324')"

$ printf %q $TESTVAR
Version:1$'\r'Build:20180712$'\r'Test:1324

来源和进一步阅读:

相关内容