CVSS 6.8 CVE-2019-6109
CVSS 6.8 CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N
An issue was discovered in OpenSSH 7.9. Due to missing character encoding in the progress display, a malicious server (or Man-in-The-Middle attacker) can employ crafted object names to manipulate the client output, e.g., by using ANSI control codes to hide additional files being transferred. This affects refresh_progress_meter() in progressmeter.c.
SCP Protocol Background
The SCP protocol is not an official standard — it is a de-facto protocol derived from the
1983 BSD rcp (remote copy) utility and was never formally documented. SCP runs over an
SSH channel: the client SSH-connects to the server and executes the remote scp binary
in file-sending mode (scp -f <file>). The two scp processes then communicate over
that channel using a simple line-oriented text protocol.
For each file the server sends, it first transmits a C-message (copy message):
C<mode> <size> <filename>\n
For example:
C0644 14295 document.txt\n
The client parses this line, extracts the filename, opens a local file with that name, and then receives the file data. Once the transfer is complete the server sends a zero-byte confirmation. The filename is taken verbatim from the C-message — the client performs no control-character filtering.
Vulnerable Code Path
After parsing the C-message, OpenSSH stores the server-supplied filename in curfile
and immediately begins rendering the progress meter via refresh_progress_meter() in
progressmeter.c. The progress display is written directly to the user’s terminal
(stderr) using atomicio():
/* progressmeter.c (simplified) */
snprintf(buf, sizeof(buf), "\r%-*s", win_size - 36, curfile);
atomicio(vwrite, STDERR_FILENO, buf, strlen(buf));
The \r at the beginning of buf moves the cursor to the start of the current line
(standard progress-meter behavior to overwrite the previous status line). If ``curfile``
itself contains ANSI escape sequences, they are written to the terminal along with the
filename — no sanitization takes place.
ANSI Escape Sequences used in the Attack
A malicious server can embed any of the following terminal control sequences in the filename portion of the C-message:
Sequence |
Effect |
|---|---|
|
Moves cursor to column 0 of the current line |
|
Erases the entire current line (cursor position unchanged) |
|
Moves cursor up one line |
|
Moves up one line and erases it completely |
The only byte that cannot appear in a filename (and therefore cannot be injected) is
\n (0x0A), because it terminates the C-message line.
Attack Chain
The attack combines this vulnerability with CVE-2019-6111 (file injection) and CVE-2019-6110 (stderr erasure):
Step 1 — Legitimate transfer begins
The client runs scp user@server:document.txt .. The server sends the expected C-message:
C0644 14295 document.txt\n
The client renders: document.txt 100% 13 KB 1.3 MB/s 00:00
Step 2 — Server injects an additional file (CVE-2019-6111)
Before the client sends its final acknowledgement, the server sends a second, injected
C-message. Per CVE-2019-6111 the client accepts arbitrary files from the server because
the SCP client-side validation only blocks ../ directory traversal — not arbitrary
target filenames.
The injected C-message uses a crafted filename containing ANSI codes:
C0600 444 \x1b[2K\rauthorized_keys\n
Broken down:
\x1b[2K— immediately erases the current terminal line (where the progress for the injected file would appear)\r— moves cursor back to column 0authorized_keys— the actual local filename the content is written to
Step 3 — Progress meter renders the crafted filename
refresh_progress_meter() writes the crafted filename to the terminal. The terminal
processes it as:
\x1b[2K→ erase the line\r→ move cursor to column 0authorized_keys→ rendered at the start of a blank line — but is immediately overwritten by the next progress update fordocument.txt
From the user’s perspective, the terminal shows only document.txt completing
normally. The injected transfer of ~/.ssh/authorized_keys is invisible.
Step 4 — Result
The client has silently written attacker-controlled content to authorized_keys
(or any other target file). The user’s terminal output shows no indication that a
second file was received.
Test with SSH-MITM
A proof of concept exploit is integrated in SSH-MITM. This exploit also uses CVE-2019-6111 to inject additional files.
To inject a file during a download from the server to the client:
$ ssh-mitm server --scp-forwarder inject_file --scp-inject /path/to/additional/file
The injected file transfer is hidden using this vulnerability and CVE-2019-6110.