Git’s implementation used to rename or delete sections of a configuration file contained a logic error that resulted in improperly treating configuration values longer than a fixed length as containing new sections.
When attempting to rename or remove a malicious configuration section, this can result in arbitrary configuration injection into a user’s .git/config. This may be used to achieve arbitrary code execution via configuration values that specify executables, such as core.pager, core.editor, and core.sshCommand.
This vulnerability may be exploited by using overly-long submodule URLs, which are stored in a user’s .git/config upon initialization. Those URLs may be misinterpreted as containing new configuration material when removing those sections, for example, with git submodule deinit.
Exploiting this issue can be complex since it requires user interaction via legitimate git commands.
CVE-2023-29007 has been assigned to this issue, with a CVSS score of 7.0/10 (high).
At Ethiack, we rely on git submodules to share common code across multiple components. First, André (0xacb) realized a weird behavior on GitHub itself, with submodule URLs that would crash the GitHub repository page, while doing bug bounties on HackerOne.
Then, we dived into the git code base and started fuzzing it. We didn’t get any crashes, but after a while, we realized that deinitializing submodules would somehow create new sections in .git/config.
In config.c, the function git_config_copy_or_rename_section_in_file uses a buffer with a length of 1024 characters. There’s no buffer overflow here since fgets is being called with sizeof(buf):
/* it's a section */
Well, what if it's not a section? :)
When we have a config file line larger than 1024 characters, fgets will be called one more time, even if there’s no new line in the config file. If the first character of the buffer, or the first character after space characters is a ‘[‘ character, a new section will be created in .git/config if the original section is being removed or renamed.
This means that any section variable larger than 1024 bytes that satisfies these conditions and is being removed by this function can end up being considered as a section instead of a variable of the original section. For instance, if we have a .gitmodules file like:
After triggering the git_config_copy_or_rename_section_in_file function, for example, by running git submodule init / deinit, the .git/config file will have a new section created that was consumed from the submodule URL above:
Other operations could lead to this behavior, such as branch deletion or removing an origin. The submodule vector is an example of injecting new sections in the git configuration file.
A repository that triggers the submodule attack vector is available at https://github.com/ethiack/CVE-2023-29007
- April 5: Vulnerability reported to the Git Security Team
- April 5: Vulnerability confirmed and CVE-2023-29007 reserved
- April 25: CVE-2023-29007 published
- April 25: Git project released new versions with the patch
This was a simple logic parsing error that could lead to local code execution while performing changes to git configuration files. If any git-based software allows the operations mentioned, it may also be exploitable.
Git 2.40.0 and older are vulnerable. Please update now.
Thanks for reading,
André Baptista @0xacb
Vítor Pinho @vgpinho