4

Consider the following scenario:

Someone, using a good version of git, issues a git clone followed by a git checkout of some commit hash (the 40 character hexadecimal).

To clarify, assume Bob does the following on a secure machine:

$ git clone https://secureserver.com/HonestEve/project.git
$ git rev-parse HEAD

which prints

5b3469eccbd7849d760f63af8537940c97c1d1bf

Bob goes over the just checked out code and verifies that it is indeed what he wants/needs.

Then at a later date, Bob does on another secure machine (or at least, in an empty directory):

git clone https://malicious.server.com/HonestEve/project.git

or probably he uses the same url, but somehow gets connected to a malicious git server. And then proceeds with:

git checkout 5b3469eccbd7849d760f63af8537940c97c1d1bf

Then the question is, is it possible (ignoring any SHA1 collisions or weaknesses) that the resulting source tree is different from what he got the first time?

Here you may assume that the git client that Bob uses is the normal, most wide-spread git client that comes with most operating systems; some recent version. Considering how this git client functions, would an attacker be able to insert malicious code into this checkout? Note that we assume the following:

1) There are no collisions possible (any SHA1 can only be gotten with the exact same input).
2) The attacker can make the victims git client connect to their own malicious server and has full control over the server, but not over the client or the machine that the client is running on.
3) The attacker knows the commit hash that the victim will use (far) in advance.

If I am correct then the attacker will not be able to do this when the client recalculates the sha1 locally from the original input to verify that the resulting checkout is what was expected. But that seems very inefficient. The size of sha1 is very large, but only intended to avoid accidental collisions it seems(?).

Surely a git checkout <sha1> will simply checkout whatever is listed under the given sha1 without any recalculation(?). However, perhaps the client verifies the correctness of the sha1's during cloning / fetching? If so, that would be paranoia and a clear effort to stop malicious attacks like the above. I am not sure that git does this.

Can anyone shine a light on this?

18
  • 2
    I'm not quite following what you are asking. Are you saying that the victim is going to checkout some git commit with a given hash, and the attacker wants to somehow get malicious code in that particular git hash? Also, in what way is this malicious commit supposed to impact the user? Feb 5, 2020 at 19:28
  • 2
    @MarcusMüller You are right of course... but still git will have an intent. If it doesn't have the intent to prevent this kind of attack then it would be highly unlikely that any recalculation is done, because it would just make things slower and not fulfill any goal. I do not know if the developers of git wanted to avoid this or not. Nor do I know what gits source code does, that is why I am asking here :/.
    – Carlo Wood
    Feb 6, 2020 at 13:36
  • 2
    @CarloWood Am I reading correctly? You're setting aside the possibility that the attacker has carefully crafted a fake source-tree that still hashes to the original, requested value. Instead, they deliver up a fake source-tree, knowing that it will hash to some unrelated value. So essentially what you are asking is whether the git client being used to retrieve the source-tree will re-compute the hash of what was actually delivered and compare it with the hash that was asked for? Is that right?
    – TripeHound
    Feb 6, 2020 at 15:14
  • 3
    "is it possible (ignoring any SHA1 collisions or weaknesses)" - Well no. If you ignore the possibility of SHA1 collisions then it is not possible to get a SHA1 collision. Feb 6, 2020 at 16:47
  • 1
    I just tried to hack a repository myself - just altered a blob without changing its name, and when I tried to clone that the client gave an error and didn't even create a directory.
    – Carlo Wood
    Feb 6, 2020 at 22:46

1 Answer 1

8

Bob goes over the just checked out code and verifies that it is indeed what he wants/needs.

Then at a later date, Bob does on another secure machine (or at least, in an empty directory):

git clone https://malicious.server.com/HonestEve/project.git

or probably he uses the same url, but somehow gets connected to a malicious git server. And then proceeds with:

git checkout 5b3469eccbd7849d760f63af8537940c97c1d1bf

Then the question is, is it possible (ignoring any SHA1 collisions or weaknesses) that the resulting source tree is different from what he got the first time?

Yes it is possible. This is not safe to do.

Mallory (the owner of malicious.server.com) can create a branch, named 5b3469eccbd7849d760f63af8537940c97c1d1bf, with arbitrary changes to the code/repository.

When Bob executes git checkout 5b3469eccbd7849d760f63af8537940c97c1d1bf, git will display a warning that the ref is ambiguous but will ultimately prefer the branch over the commit. (note if this gets run in e.g. a build script, you will likely miss the warning)

I have tested this just now on git 2.25.1 (on Ubuntu 20.04).

I have also tested pushing such a branch to GitHub - but that failed. GitHub seems to have a custom check that ensures that branches/tags cannot have a 40-hex character name:

[...]
remote: error: GH002: Sorry, branch or tag names consisting of 40 hex characters are not allowed.
remote: error: Invalid branch or tag name [...]

However, this check is specific to GitHub; and even pulling from GitHub note that you now not only need to trust git but GitHub too.

The solution to this specific attack vector is to tell git that the ref you want is a commit hash:

git checkout 5b3469eccbd7849d760f63af8537940c97c1d1bf^{commit}
2
  • Thanks for pointing out this vulnerability. But it doesn't answer my question on whether or not the git client recalculates sha1 and thus verifies the checked out code (in case you actually check it out by hash - ie, by adding ^{commit}).
    – Carlo Wood
    Jun 26, 2020 at 19:43
  • 2
    @CarloWood the client does not trust the server and will recalculate hashes on all objects it receives specifically to counter an attack like the one you describe. See this thread: lore.kernel.org/git/…
    – mricon
    Jun 28, 2020 at 13:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .