我有一个简单的问题。
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
来源和进一步阅读: