Terminal escape sequences – the new XSS for Linux sysadmins

Mattias Geniar, Thursday, September 24, 2015 - last modified: Friday, September 25, 2015

A couple of weeks ago, the OSS-security mailinglist got a really interesting thread about the dangers of escape sequences inside a terminal. It didn't really get a lot of attention back then but the follow-up thread made by Frederico Bento did.

These techniques have been known for many years (especially since escape sequences go way back), but I have to admit -- I wasn't aware of this kind of impact.

How it technically works:
A terminal escape sequence is a special sequence of characters that is printed (like any other text).
If the terminal understands the sequence, it won't display the character-sequence, but will perform some action.
s/party/hack like it's 1999

Escape sequences allow you to do funny things like write blinking commit messages, but there's a darker side to them as well.

The example below illustrates the real danger of escape sequences.

$ printf '#!/bin/bash\necho doing something evil!\nexit\n\033[2Aecho doing something very nice!\n' > backdoor.sh

$ chmod +x backdoor.sh

$ cat backdoor.sh
echo doing something very nice!

$ ./backdoor.sh
doing something evil!

(if you are going to test this, it's important to have the printf-line be on a single line, without additional new lines)

Here's what happened:

  1. A cat of the file did not show all the content in plain text, it interpreted the escape sequences and executed an action.
  2. Executing the file then executed code that did not show up in the cat of that same file.

It's important to remember: we can't trust cat at the command line.

Protecting yourself from malicious escape sequences

While it's never been safe to just run curl installscript.tld | bash from any site on the internet, these escape sequences show that downloading the file first and inspecting it with cat (or more, head, tail, ...) can trick even experienced sysadmins.

There are a couple of ways to protect you from this.

cat -v $file

The -v parameter shows all non-printable characters (which seems like a safe default to have, odd that it isn't? Update: turns out, not a good idea to have as a default.).

$ cat -v backdoor.sh
echo doing something evil!
^[[2Aecho doing something very nice!

cat $file | xdd

Catting a file and piping it to xxd (a hexdumper) will show you the escape characters as well.

$ cat backdoor.sh  | xxd
0000000: 2321 2f62 696e 2f62 6173 680a 6563 686f  #!/bin/bash.echo
0000010: 2064 6f69 6e67 2073 6f6d 6574 6869 6e67   doing something
0000020: 2065 7669 6c21 0a65 7869 740a 1b5b 3241   evil!.exit..[2A
0000030: 6563 686f 2064 6f69 6e67 2073 6f6d 6574  echo doing somet
0000040: 6869 6e67 2076 6572 7920 6e69 6365 210a  hing very nice!.

less $file

The old saying of "less is more" is true here as well, since less will show the escape sequences by default.

$ less backdoor.sh
echo doing something evil!
ESC[2Aecho doing something very nice!
backdoor.sh (END)

Let's all agree to never trust anything that has been posted on the internet without very thorough inspection. And let's especially agree to never run an arbitrary command or script found on the internet, without really close inspection.

If you're up for some more reading, the original oss-security thread has some impressive examples on how to fool diff and gcc compilation as well.

Hi! My name is Mattias Geniar. 👋 I'm an independent software developer ⌨️ & Linux sysadmin 👨‍💻, a general web geek & public speaker. Currently working on DNS Spy & Oh Dear! Follow me on Twitter as @mattiasgeniar 🐦.

🔥 If you're stuck with a technical problem, I'm available for hire to help you fix it!

Share this post

Did you like this post? Help me share it on social media! Thanks. 🤗

Have feedback?

New comments have been disabled on this blog, existing comments will remain as-is. Want to give feedback? Is there a mistake in the post?

Send me a tweet on @mattiasgeniar!


Jeremy Chadwick Friday, September 25, 2015 at 05:42 -

With regards to this comment: “The -v parameter shows all non-printable characters (which seems like a safe default to have, odd that it isn’t?).”

No, the -v parameter SHOULD NOT be the default. It IS NOT a safe default. Anyone who says otherwise is wrong. No wiggle room: flat out wrong. Please consider the implications of making -v the default; consider situations like the below, which are *incredibly* common and are common convention/operation in the *IX and UNIX world and have been for ~40 years:

tar -zpcf - /somedir | ssh user@host "cat > /somedir.tar.gz"

Please think about what would happen if -v was the default in that scenario.

This whole debacle was already covered back in 1983 as well: http://harmful.cat-v.org/cat-v/

It seems to me that escape sequences and “general terminal behaviour” (and understanding ptys/ttys) is something of a “dying art”, meaning *IX users today seem to think that terminals are some kind of “black magic” and that certain behaviours that are absolutely expected/normal should be changed or inhibited because of their lack of knowledge of history or the “whys” of said decisions long ago. My gut feeling is that these, and several other aspects, of terminals and ptys/ttys were never fully passed on to younger *IX users by senior sysadmins like myself, including the nuances of use of things like GNU screen and the caveats of such (terminal-wise). For that I apologise, although I do regularly pass on terminal and escape sequence knowledge every chance I get; for example: http://lists.freebsd.org/pipermail/freebsd-stable/2011-June/063052.html

Random footnote: xxd is not available on all *IX systems. Alternates may include hexdump (also not available on every *IX), hd (also not available on every *IX*), and od (octal dump — yes, you can use this on things like classic Solaris, but not available on other *IX).

Francis Kim Friday, September 25, 2015 at 15:24 -

Some great insight in this article – thank you, I’ll be forwarding this to my sysadmin friends :)

Joseph Scott Tuesday, September 29, 2015 at 21:57 -

Same problem, new environment. This was a problem for many back in the MS-DOS days, with ANSI.SYS allowing your do similar attacks. Things like remapping the return key to delete the C drive.

Everything old is new again :-)

Hanno Saturday, November 14, 2015 at 19:58 -

Actually I’m not sure less is exactly the best tool to investigate suspicious content.
In most linux distros less will pass the input through a script called lesspipe that will – depending on the extension – run all kinds of tools that will try to interpret it in some way.
I’ve tried to start an effort to get some of these tools to be more resilient against attacks (actually this was one of the motivating factors to start the Fuzzing Project), but many of them were simply unmaintained and for some the fixing process took extremely long.

I once had the idea to create a “safer” version of lesspipe that would only include tools that were thoroughly tested with fuzzing, but never got to implement it.

Inbound links