on
Compromise On Checkout - Vulnerabilities in SCM Tools
First Round: Git LFS
In mid May 2017, I was about to go on my two month parental leave, when I stumbled across
a nifty vulnerability in Git LFS, which is
developed by the fine people at GitHub. The actual vulnerability was shockingly
simple: Git LFS can be configured (partially) by a .lfsconfig
file within the
repository utilizing LFS and it was possible to point Git LFS to crafted
ssh://
URLs of the following form:
[lfs]
url = ssh://-oProxyCommand=some-command
When cloning a repository with such a .lsfconfig
file, Git with the LFS plugin
would happily try to invoke ssh in order to get the LFS objects from a host
-oProxyCommand=some-command
. SSH, however, would interpret that hostname as
an -o
option and subsequently try to invoke some-command
in order to establish a
connection (see also man 5 ssh_config
).
So, arbitrary command execution was possible via a crafted repository for Git LFS clients, which clone the repository. This issue was disclosed to GitHub and has been resolved in a very quick fashion.
Despite this attack vector being relatively “old-school” (see CVE-2004-0489) it turned out to affect more than just Git LFS.
So, let’s now skip over two months of (almost) full time parenting during my leave ;).
Second Round: Git(Lab)
Mid July 2017, I was back at the Recurity Labs office and the first project
after a two months hacking hiatus was an assessment on
GitLab. I quickly discovered a Command Execution issue by
using the very same trigger as for Git LFS. By importing a repository in a new
project with an ssh://
, URL server-side code execution was possible on a
GitLab host. I was obviously happy to start with an RCE on the first day after
the break. However, this issue, when taking a closer look, was beyond LFS and
GitLab; it affected git clone
directly.
For instance, the following command line would pop a gnome-calculator
:
$ git clone ssh://-oProxyCommand=gnome-calculator/wat
Cloning into 'wat'...
Pseudo-terminal will not be allocated because stdin is not a terminal.
ssh_exchange_identification: Connection closed by remote host
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
While it might be tricky to convince a user to clone a repository with
a rather shady looking ssh://
URL, this attack vector is exploitable in a more
sneaky way when it comes to Git submodules. So, it is possible to create a Git
repository that contains a crafted ssh://
submodule URL. When such a
repository is cloned recursively, or the submodule is updated, the ssh://
payload
will trigger.
Brian Neel, who was Recurity Labs’ contact at GitLab for the assessment, exemplary coordinated the disclosure to the closed git-security list.
Third Round: SVN and Mercurial
Within the process of creating a fix for Git, two more vulnerabilities surfaced:
The very same issue affected SVN and Mercurial as well. After double checking,
it could be confirmed that SVN was affected in the worst way:
SVN follows HTTP 301 redirects to svn+ssh://
URLs. As a result, an innocent
looking HTTP URL can be used to trigger a Command Execution with a 301
redirect.