Skip to content

Commit

Permalink
fix(git-checkout): fix a critical security issue reported by @drivertom
Browse files Browse the repository at this point in the history
the security issue would lead to arbitrary file writing on the user's machine,
which could be extremely dangerous when some critical file be overwritten (eg:
the crontab file, ssh-keys) The root cause of this issue is that the .git
folder leakage is an abnormal scene of manipulating the git repository. When we
executing `git clone`, there are multiple steps to do.

1. download the internal objects into the `.git` folder and **CHECK the
VALIDITY** of all object files.
2. perform `checkout` to extract the current content of the `.git` folder. git
will completely *TRUST* the object files of the .git folder cause they are
already be checked.

But when hackers use `GitHacker` (or other similar tools like git-dumper) to
exploit the `.git` folder leakage vulnerability. These tools will just simply
download the `.git` folder directly, then perform `git checkout .`.

The critical thing is that the developer of these tools just trusts the `git
checkout .` will do the check, but unfortunately, `git checkout .` doesn't. git
assume that before checking out, the .git folder is already been verified.

To **fix** this issue, I just use `git clone instead of `git checkout .` (`git
clone` is able to clone a folder on the file system, ref:
https://git-scm.com/docs/git-clone#_git_urls). It's a simple but dirty fix. The
best way to fix this issue is to let git verify the .git folder when performing
`checkout`, but it seems that is not possible. :(

To **summarise**, git does the right thing, the developer does the right thing
too. All the evil thing comes from the weird scenario of git leakage.
  • Loading branch information
WangYihang committed Aug 14, 2021
1 parent ecc1f2c commit e105b5c
Showing 1 changed file with 18 additions and 10 deletions.
28 changes: 18 additions & 10 deletions GitHacker/__init__.py
Expand Up @@ -9,6 +9,9 @@
import subprocess
import argparse
import bs4
import tempfile
import shutil


__version__ = "1.0.10"

Expand All @@ -24,7 +27,8 @@ class GitHacker():
def __init__(self, url, dst, threads=0x08, brute=True) -> None:
self.q = queue.Queue()
self.url = url
self.dst = dst
self.dst = tempfile.mkdtemp()
self.real_dst = dst
self.repo = None
self.thread_number = threads
self.max_semanic_version = 10
Expand Down Expand Up @@ -63,7 +67,7 @@ def directory_listing_enabled(self):
def sighted(self):
self.add_folder(self.url, ".git/")
self.q.join()
self.checkout()
self.git_clone()

def add_folder(self, base_url, folder):
url = "{}{}".format(base_url, folder)
Expand Down Expand Up @@ -103,7 +107,6 @@ def blind(self):
content = "{}".format(subprocess.run(
['git', "fsck"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=self.dst,
))
tn = self.add_hashes_parsed(content)
Expand All @@ -112,18 +115,23 @@ def blind(self):
else:
break

self.checkout()
self.git_clone()

def checkout(self):
logging.info("Checkout files...")
subprocess.run(
["git", "checkout", "."],
def git_clone(self):
logging.info("Cloning downloaded repo from {} to {}".format(self.dst, self.real_dst))
result = subprocess.run(
["git", "clone", self.dst, self.real_dst],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=self.dst
)
if b"invalid path" in result.stderr:
logging.info("Remote repo is downloaded into {}".format(self.real_dst))
logging.error("Be careful to checkout the source code, cause the target repo may be a honey pot.")
logging.error("FYI: https://drivertom.blogspot.com/2021/08/git.html")
else:
logging.info("Check it out: {}".format(self.real_dst))
shutil.rmtree(self.dst)

logging.info("Check it out in folder: {}".format(self.dst))

def add_hashes_parsed(self, content):
hashes = re.findall(r"([a-f\d]{40})", content)
Expand Down

0 comments on commit e105b5c

Please sign in to comment.