CVSS 5.9 CVE-2019-6111
CVSS 5.9 CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N
An issue was discovered in OpenSSH 7.9. Due to the scp implementation being derived from 1983 rcp, the server chooses which files/directories are sent to the client. However, the scp client only performs cursory validation of the object name returned (only directory traversal attacks are prevented). A malicious scp server (or Man-in-The-Middle attacker) can overwrite arbitrary files in the scp client target directory. If recursive operation (-r) is performed, the server can manipulate subdirectories as well (for example, to overwrite the .ssh/authorized_keys file).
SCP Protocol: Server Controls Which Files Are Sent
The SCP protocol is derived from the 1983 BSD rcp (remote copy) utility. When a user
runs scp user@server:document.txt ., the client connects via SSH and executes the
remote scp binary in source mode (scp -f document.txt). The server-side
scp process then decides what to send using a simple line-oriented protocol over the
SSH channel.
For each file, the server sends a C-message (copy message):
C<mode> <size> <filename>\n
Example for a legitimate transfer:
C0644 14295 document.txt\n
The client parses this line, opens a local file with the given <filename>, receives
<size> bytes from the channel, and stores them. The critical design flaw from the
rcp heritage: the client does not verify that the server-supplied filename matches
what was requested. The protocol gives the server full control over which files end up
on the client’s filesystem.
What Validation Does (and Doesn’t) Exist
The SCP client does perform one check on the server-supplied filename: it rejects names
containing ../ (and ..\\ on Windows). This prevents the most obvious directory
traversal attacks such as the server sending:
C0644 444 ../../.bashrc\n
However, this check does nothing to prevent the server from sending:
A completely different filename than what was requested (e.g.,
authorized_keysinstead ofdocument.txt)Dotfiles (e.g.,
.bashrc,.profile)Files with the same name as executables or configuration files in the target directory
In recursive mode (
scp -r): files in subdirectories, including.ssh/
The client simply accepts and writes every C-message the server sends, as long as the
filename passes the ../ check.
Attack Chain
Setup: An SSH-MITM attacker intercepts the connection between a victim running
scp user@server:document.txt . and the real server.
Step 1 — Relay legitimate file
The attacker forwards the real document.txt from the server to the client:
C0644 14295 document.txt\n
[14295 bytes of document content]
Step 2 — Inject additional file
Before the SCP session ends, the attacker injects an additional C-message with an arbitrary filename, e.g.:
C0600 89 authorized_keys\n
ssh-ed25519 AAAA... attacker@evil\n
The client receives this as a second file and writes 89 bytes to ./authorized_keys
in the local target directory — silently overwriting the user’s SSH authorized_keys file
if the target directory is ~/.ssh/.
Step 3 — Hide the injection
The injected transfer is visible in the SCP progress display unless hidden using:
CVE-2019-6109 — ANSI escape codes in the filename erase the progress line
CVE-2019-6110 — stderr codes sent by the server erase the progress line independently
Recursive Transfer Variant
With scp -r user@server:project/ . (recursive download), the server controls the
entire directory structure. The server can inject files into any subdirectory by sending
D-messages (directory creation):
D0700 0 .ssh\n ← creates .ssh/ subdirectory
C0600 89 authorized_keys\n
[key content]
E\n ← end directory
This allows the attacker to overwrite ~/.ssh/authorized_keys regardless of the
initial target directory, as long as the user’s home directory is reachable relative
to the SCP destination.
Test with SSH-MITM
A proof of concept exploit is integrated in SSH-MITM. The injected file transfer is hidden using CVE-2019-6109 and CVE-2019-6110.
$ ssh-mitm server --scp-forwarder inject_file --scp-inject /path/to/additional/file