Can "cat-ing" a file be a potential security risk?
Yes, it's a potential risk, see CVE-2003-0063, or CVE-2008-2383 or CVE-2010-2713, or CVE-2012-3515 or OSVDB 3881, or CVE-2003-0020 or any of the similar ones listed here... Some more in comments below also.
Update it's not just a potential risk, it's a real risk. rxvt-unicode (versions 2.7—9.19, patched in 9.20) allows read/write access to X window properties, this can enable user-assisted execution of arbitrary commands, this issue has been assigned CVE-2014-3121, more details here https://bugzilla.redhat.com/show_bug.cgi?id=1093287 .
More recently (October 2019) iTerm2 versions up to v3.3.5 were found to have the same class of problem: display of malicious content can enable the integrated tmux and permit command execution, see CVE-2019-9535.
This topic also has good coverage here: https://unix.stackexchange.com/questions/73713/how-safe-is-it-to-cat-an-arbitrary-file and a thorough analysis of the underlying problem from Gilles here: https://unix.stackexchange.com/questions/15101/how-to-avoid-escape-sequence-attacks-in-terminals .
Explanation
What you are observing is a side-effect of how certain escape sequences behave: some of them stuff characters (usually also containing escape sequences) directly into the terminal input buffer. All in the name of backward compatibility, of course. The standard xterm
escapes which are described using the term "Report <something>" do this. This behaviour permits programs to query/set terminal (or other) properties "in band" rather than via ioctls or some other API.
As if that wasn't bad enough, some such sequences can contain a newline, which means that whatever is reading from the terminal (your shell) will see what appears to be a complete user command.
Here's a neat way to use this, with bash's read
to print an escape (as a prompt) then immediately read and split the reply into variables:
IFS=';' read -sdt -p $'\e[18t' csi8 rows cols
echo rows=$rows cols=$cols
These sequences can vary by terminal, but for rxvt
and derived, the graphics query escape includes a newline (example using bash
and $''
strings, see doc/rxvtRef.txt
in the source)` :
$ echo $'\eGQ'
$ 0
bash: 0: command not found
This escape sends \033G0\n
into the terminal input buffer (or digit 1
instead of 0
if you have a graphics-capable rxvt
).
So, combine this escape with other sequences which behave similarly:
echo $'\x05' $'\e[>c' $'\e[6n' $'\e[x' $'\eGQ'
for me this causes 11 attempts to run various commands: 1
, 2c82
, 20710
(my rxvt
version string), 0c5
, 3R
(5 and 3 were the cursor coords), 112
and 0x0
.
Exploitable?
With rxvt
and most recent terminal emulators you should "only" be able to create a limited set of mostly numeric sequences. In old terminal emulators it was possible (some CVEs listed above) to access the clipboard, the window icon and titlebar text to construct more malicious strings for invocation (one current slight exception is if you set the answerbackString
X resource string, but that cannot be directly set using this method). The flaw then is allowing arbitrary read and write access to something that passes for state or storage within escape sequences that stuff data into the input buffer.
rxvt
requires compile time changes to activate, but urxvt
helpfully has an -insecure
command line option that enables some of the more exciting features:
$ echo $'\e]2;;uptime;\x07' $'\e[21;;t' $'\eGQ'
bash: l: command not found
17:59:41 up 1448 days, 4:13, 16 users, load average: 0.49, 0.52, 0.48
bash: 0: command not found
The three sequences are:
\e]2;...\x07
set window title;\e[21;;t
query window title, place in input buffer;\eGQ
query graphics capability, which adds\n
to input buffer.
Again, depending on terminal, other features such as font size, colors, terminal size, character set, alternate screen buffers and more may be accessible though escapes. Unintended modification of those is at least an inconvenience, if not an outright security problem. Current versions of xterm
restrict potentially problematic features via "Allow*" resources.
CVE-2014-3121
Prior to v9.20, urxvt
did not also guard read and write access to X properties (mostly used by window managers). Write read access (or more precisely, access to sequences which echo potentially arbitrary strings) now requires the -insecure
option.
$ echo $'\e]3;xyzzy=uptime;date +%s;\x07'
$ xprop -id $WINDOWID xyzzy
xyzzy(UTF8_STRING) = 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x3b, 0x64, 0x61, 0x74, \
0x65, 0x20, 0x2b, 0x25, 0x73, 0x3b
This can be trivially used to stuff arbitrary strings into the terminal input buffer. When the escape sequence to query a property is invoked (along with helpful \eGQ
which adds a newline):
$ echo $'\e]3;?xyzzy\x07' $'\eGQ'
$ 3;uptime;date +%s;0
bash: 3: command not found
17:23:56 up 1474 days, 6:47, 14 users, load average: 1.02, 1.20, 1.17
1400603036
bash: 0: command not found
Multiple commands, preserving whitespace and shell metacharacters. This can be exploited in a variety of ways, starting with cat-ing an untrusted binary of course, further ideas in H.D. Moore's short paper (2003).
Followup
For the escape sequence you ask about: 1;112;112;1;0x1;2
This is: Request Terminal Parameters (DECREQTPARM) and Send Device Attributes :
$ echo $'\e[x' $'\e[0c'
;1;1;112;112;1;0x1;2c
The second one (\e[0c
) is the same as ^E
(using rxvt
). There are some escape sequences in there too. the full sequence written for each is, respectively:
\e[1;1;1;112;112;1;0x
\e[?1;2c
Definitively yes.
New add 2020-01-25:
From time I've switched from LATIN-1
encoding to UTF-8
as default encoding in most of my systems, I've found some interresting features around this (there are now two lenght for one string)...
For sample, as I like to play with bash, I've asked why bash localization won't work with multilines strings. This bash feature
present a bug, where workaround consist of using eval
. If this is not
a security flaw, this could become or produce one...
In every evolutions of almost anything (languages, libraries, tools, protocols, applications, hardware, installers, consoles, etc...) comme new features, with potentially new bugs...
Fortunately, they are as few as they are quickly corrected (near one-day from reveal), but they are!
So definitively yes, stay care!
Correct use of cat
command.
As you seem to be using a modern terminal emulator, some escape sequences could be used to modify Keyboard buffer.
There could be proper shell commands injected.
You could use argument -e
of cat
for safe operation, see man cat
.
-e equivalent to -vE -E, --show-ends display $ at end of each line -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
Then
$ cat -e suspectfile.raw
$ cat -e suspectfile.raw | less
or under bash:
$ less < <(cat -e suspectfile.raw)
or even
$ which less cat
/usr/bin/less
/bin/cat
$ rawless() { /usr/bin/less < <(/bin/cat -e "$@");}
Remarks
When you read command not found
, this implies that something was effectively injected.
The main injection feature that was not removed is the sequence indentify yourself, used in many VT-100 encapsulation.
This sequence is Escape Z
which will inject the string 1;2c
into your keyboard buffer, which means VT-100
(in AVO convention).
Speaking about cat
, you could try:
$ cat <<< $'\033Z'
Or another ANSI sequence: CSI c
(Device Attributes):
$ cat <<< $'\033[c'
will print an empty line, but on next line prompted, you will see 1;2c
(or maybe with another numbers, depending on terminal used) as if you hitted them:
$ 65;1;9c█
... but with -e
switch:
$ cat -e <<< $'\033Z'
^[Z$
$ cat -e <<< $'\033[c'
^[[c$
Where -e => -vE
, -v
transform \033
into ^[
and -E
put a $
sign at end of line (and nothing will be put on next line, you keyboard buffer is not affected).
You may find lot of funny things at VT100 User Guide (like: cat <<< $'\033#8'
;)
(They was modern terminal! In some past... )
Trying using bash
There is a little bash command for flushing keyboard buffer and get his content:
$ cat <<<$'\033[c';buf='';while read -t .1 -n 1 chr;do
buf+="$chr"
done;printf "\n>|%q|<\n" $buf
^[[?65;1;9c
>|$'\E[?65;1;9c'|<
And a little function to test any chain:
$ trySeq() {
printf -v out "$1"
echo -n "$out"
buf=""
while read -t.1 -n1 char
do buf+="$char"
done
[ "$buf" ] && printf "\r|%q|->|%q|<\e[K\n" "$out" "$buf"
}
So I could try:
$ for seq in $'\e['{c,{1..26}{n,t,x}};do
trySeq "$seq";done
|$'\E[c'|->|$'\E[?65;1;9c'|<
|$'\E[1x'|->|$'\E[3;1;1;120;120;1;0x'|<
|$'\E[5n'|->|$'\E[0n'|<
...
( Maybe with some harmless effects on your console ;)
Small practical sample
Imagine, some could put something like this in your environment:
$ source <(printf '%dc() {
printf "You\\047ve been hitted\\041\\n"
};\n' {0..100};printf 'alias %s=1c\n' {0..100};)
Then, if you
$ cat <<<$'\e[c'
$ 65;1;9c█
Cursor will stay at end of command prompt line.
From there, if you machinally hit Return instead of Ctrl+c, you will read something like:
$ 65;1;9c
You've been hitted!
You've been hitted!
You've been hitted!
$ █
And now?
From there, unfortunately, there is no standard.
Every virtual terminal implementation could support full ANSI and/or full DEC standard...
But as there are some security issues, many don't...
You could observe some behaviour using one terminal that you wouldn't observe using another...
xterm, linux console, gnome-terminal, konsole, fbterm, Terminal (Mac OS)... the list of terminal emulators is not so short!
And each of them has its own bugs and limitations compared to DEC and ANSI standards.
In pactice, you may find some virtual console that could be more featured than other and where keyboard injection could break your security.
It's one of the reasons because I prefer to use alway same (old) xterm
rather than other more featured tools.
"Real" glass terminals had an escape sequence to print the screen to a printer. They did this by running a command and pipeing the current screen contents to the stdin of the print command.
The command could be configured by another escape sequence.
The classic way of exploiting this was to create files with names that embedded the escape sequence to set the printer command and change it to some script of your choice and then have a 2nd file with the print escape sequence in it.
When someone then ran ls
in that directory they would end up running your code. Which was nice if they were the root
user!
In theory modern terminal emulators shouldn't do that kind of thing any more.
Terminal.app appears to be based on the NextStep nsterm, so it may have all kinds of weirdness in it.
Maybe try narrowing down which exact bytes are producing the command not found
messages?
Looks like there are escape sequences to raise and lower the terminal:
http://the.taoofmac.com/space/apps/Terminal
some more info here:
http://invisible-island.net/ncurses/terminfo.src.html#toc-_Apple__Terminal_app
If you want to send content to a program's stdin,
program -para meters < /path/file.ext