Terminal escape sequences – the new XSS for Linux sysadmins

Image of Mattias Geniar

Mattias Geniar, September 24, 2015

Follow me on Twitter as @mattiasgeniar

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
#!/bin/bash
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
#!/bin/bash
echo doing something evil!
exit
^[[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
#!/bin/bash
echo doing something evil!
exit
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.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.