This post is the second part of the story of a vulnerability that could be leveraged as a supply chain attack and used to hack millions of software developers around the world.
We will describe all details about CVE-2020-26233, a vulnerability affecting all versions below 2.0.280 of Git Credential Manager Core in Github CLI tool (also called gh) for Windows.
Description of the issue
This issue was similar to the Github for Desktop remote code execution we discovered and published in our blog, but this time another component has been affected: Git Credential Manager Core.
By default when Git clones a repository with submodules it first clones the repo's top-level and then recursively clones the submodules. However, when doing so it starts a new Git process from inside the top-level directory.
If a malicious executable named git.exe was placed in the root directory of the repo, this binary will be called by Git Credential Manager Core when attempting to read configuration. The cloning process happens normally and there is no visual indication that a malicious binary was ran instead of the original git executable.
Since our first report in November 2020, a library SafeExec was created by Github to mitigate the risks brought by the discrepancy in the search order of binaries in Windows.
As a quick recap, Windows first checks for the presence of a given binary in the current folder and only if it is not found, traverses the directories in %PATH% environment variable until it finds the executable in question.
In the gh version 1.2.1 the function safeexec.LookPath has been introduced, in theory not allowing for remote code execution when cloning a new repository by abusing the Windows path search order.
Upon a closer look into it, our security engineer Vitor Fernandes discovered a bypass that could be exploited to achieve RCE just like before.
During the vulnerability discovery process, Blaze noticed that when forking a new private repository, a remote code execution scenario was still possible because after cloning the command git.exe config credential.namespace is called without the safeexec.LookPath function, so Windows will fallback to its default and search for the git.exe binary in the current cloned repository:
From the code in src/shared/Microsoft.Git.CredentialManager/CommandContext.cs:
As we can see, in the line 89 a new process will be created searching for git.exe, and as directory path arguments, the Environment.LocateExecutable('git.exe') will be passed to the GitProcess() function.
The image below shows the Environment.LocateExecutable() function:
The code for function environment.TryLocateExecutable can be found here:
When using the Window's utility where.exe it returns ALL occurrences of a file or command, including the values of %PATH% and the current directory, as explained in this StackOverflow thread
Exploiting the vulnerability
The following steps are required to exploit the issue:
- a) Create a new repository or the ability to add files to an existing one;
- b) Upload a Windows executable to this repository and rename it to git.exe;
- c) Wait for the victim to fork the repository
- d) Enjoy your shell
In the example below, calc.exe was renamed to git.exe and pushed into the repository:
Upon forking the repo with the command gh repo fork REPOSITORY_NAME --clone the calculator pops up:
Patches and workarounds
GCM Core version 2.0.289 contains the fix for this vulnerability. It is also bundled in Git for Windows version 2.29.2(3).
A suggested workaround from  instructs users to avoid recursively cloning untrusted repositories using the --recurse-submodules command line switch.
The commit 5b4a08dcb9bc63f8da5f966b4e47d73edf87f3b7 introduces a fix to this vulnerability.
The vulnerability was discovered and researched by Vitor Fernandes of Blaze Information Security.