I have one quick question.
Is it normal that bash (i am using 4.4.11) is not displaying lines/text that is separated / end with plain \r
?
I was a bit surprised to see this behavior:
$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george
But "hello again" text is still there,somehow "hidden":
$ 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
And as soon as we just play with bash is fine…. But is this a potential security risk? What if contents of variable "a" come from outter world and include "bad commands" instead of just hello?
Another test, a bit unsecure this time:
$ 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>
Imagine a hidden rm
instead of a hidden ls
.
Same behavior when using echo -e:
$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George
Is it me that does something wrong…?
Best Answer
Your
echo "$a"
prints "hello", then goes back to the beginning of the line (which is what\r
does), print "again", goes back again, prints "george", goes back again, and goes to the next line (\n
). It’s all perfectly normal, but as chepner points out, it doesn’t have anything to do with Bash:\r
and\n
are interpreted by the terminal, not by Bash (which is why you get the full output when you pipe the command tood
).You can see this better with
since that will leave the end of the overwritten text:
You can’t really use that to hide commands though, only their output (and only if you can be sure to overwrite with enough characters), unless using
eval
as you show (but usingeval
is generally not recommended). A more dangerous trick is using CSS to mask commands intended to be copied and pasted from web sites.