Is using 'echo' to display attacker-controlled data on the terminal dangerous?
Is it possible for an attacker, regardless of how unlikely it would be, to exploit this somehow by modifying the content of attackerControlledFile.txt? "Somehow" refers to things like:
This code requires the output to be printed onto a specific terminal emulator
In fact, yes. Old terminals like vt100 have the ability to use ANSI escape sequences to do special things, like execute commands. The following site below documents this ability using a simple echo, like you describe.
https://www.proteansec.com/linux/blast-past-executing-code-terminal-emulators-via-escape-sequences/
The article is in depth with specific exploit instructions, but the general idea can be summarized from this excerpt from the site:
Dangerous Escape Sequences Terminal emulators support multiple features as described below [8]:
Screen Dumping: a screen dump escape sequence will open arbitrary file and write the current content of the terminal into the file. Some terminal emulators will not write to existing files, but only to new files, while others will simply overwrite the file with the new contents. An attacker might use this feature to create a new backdoor PHP file in the DocumentRoot of the web server, which can later be used to execute arbitrary commands.
Window Title: an escape sequence exists for setting the window title, which will change the window title string. This feature can be used together with another escape sequence, which reads the current window title and prints it to the current command line. Since a carriage return character is prohibited in the window title, an attacker can store the command in a window title and print it to the current command line, but it would still require a user to press enter in order to execute it. There are techniques for making the command invisible, like setting the text color to the same color as the background, which increases the changes of user pressing the enter key.
Command Execution: some terminal emulators could even allow execution of the command directly by using an escape sequence.
As pointed out in the comments, this particular exploit was fixed decades ago on modern terminal emulators. This just happened to be a simple example that a 30 second Google search revealed that nicely demonstrates the concept that there's still software at work that could be exploitable even in something as simple as displaying a file.
Theoretically, there could be other problems with modern terminal emulators (buffer overflows?) that might be exploitable.
If the output is going to a terminal, you have potentially lots of problems (regardless of how you print it, unless you strip special characters), as per other answers.
If the file can be gigantic, the attacker can make bash
use a lot of RAM. Consider head -c 100000
instead of cat
to set an upper limit of 100kB. Or head -c 10000 | cat -v
(show non-printing characters as ^M
or whatever; may break UTF-8 multi-byte characters).
If you want the data to potentially be giant, consider running that command directly (not inside a var=$()
capture), with the output of cat
connected to your stdout directly.
Since you have the data in shell variable, not being eval
ed inside double quotes, you're safe from some things.
e.g. command substitution won't work.
peter@volta:/tmp$ foo='$(touch bar)'
peter@volta:/tmp$ echo "${foo}"
$(touch bar)
An attacker can munge the output slightly by using the string -n
, which echo
will interpret as an option instead of literal data.
$ echo "-n" # notice that this doesn't print a newline.
$ echo "" # unlike a normal echo "" or echo with no args
$
But bash's builtin echo
doesn't treat "-n foo"
as an option; it's printed literally:
$ echo "-nabcd"
-nabcd
Since you expand the shell variable inside double quotes, there's no way for it to become multiple args for echo, like echo "-n" "leave the cursor at the end of this string"
Similarly -e
isn't possible, and isn't a danger anyway because your file can already contain arbitrary binary data.
/bin/echo
from GNU Coreutils supports a --version
option, so if you're not using a shell builtin echo then an attacker could get your program to print software version info. If that output ends up in something attacker-visible, it discloses some info about the target system.
For these reasons, the recommendation for portably printing arbitrary data is:
printf "%s\n" "${ATTACKERDATA}"
Works on all POSIX shells, not subject to the system-specific vagaries of echo
.
https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo/65819
https://unix.stackexchange.com/questions/58310/difference-between-printf-and-echo-in-bash
But note this does nothing about terminal vulnerabilities, it's just a safe way to write any data literally without echo
munging it.
And binary data still treats \0
(a zero byte) as a terminator in most shells, because bash internally uses C strings. The OS execve
interface also uses C strings, but shell builtins allow shells to bypass that for echo
/ printf
, so it is possible for e.g. zsh
to echo / printf binary data containing zero bytes.
And BTW, in bash you don't actually need cat
to read a file. Command substitution with a redirect gets bash to do the reading itself.
ATTACKERDATA="$(< attackerControlledFile.txt)"
But if you want any processing, like head -c
and/or cat -v
, you should use a real command.
Some terminals can echo back screen content as-if typed.
Thus you can possibly force "typing" and thus command execution with the right terminal commands. I have done this on physical DEC VT62-t
s. but have not tried to do it with the VT-52 mode of X-term
this exploit is well known, and is probably the reason why finger -l username
strips all control characters (except newline and tab) from ~username/.plan
etc
so yes it's dangerous. to make it safe pipe it through less or col etc.