Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timeout,proxy and rce fix #43

Merged
merged 6 commits into from
Mar 5, 2024
Merged

Timeout,proxy and rce fix #43

merged 6 commits into from
Mar 5, 2024

Conversation

srozb
Copy link
Contributor

@srozb srozb commented Feb 29, 2024

3 commits stacked here:

  1. Timeout was not applied to the first request and therefore causing script to stuck if target was not responding.
  2. As mentioned in Security risk - RCE in .git/config #42, potential dangerous variables in .git/config file may cause RCE. This commit tries to comment out lines that may be unsafe - feel free to add more patterns of such lines. I'm aware this is not a perfect solution but at least some kind of protection.
  3. I'm not sure if proxy configuration was applied to git command issued as a subprocess. This commit adds environment variable ALL_PROXY to ensure git communication uses configured proxy.

@srozb srozb changed the title Socks fix Timeout,proxy and rce fix Feb 29, 2024
Copy link
Owner

@arthaud arthaud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this. I wrote down some comments.

git_dumper.py Outdated

printf("[-] Running git checkout .\n")
os.chdir(directory)
subprocess.check_call(["git", "checkout", "."])
ENV = os.environ
Copy link
Owner

@arthaud arthaud Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shouldn't modify the current environment in case someone uses git-dumper as a library (although unlikely). We can simply make a copy.
Also, nitpicking but I would just call it "environment". ENV makes it seem like it's a global variable, which it isn't.

Suggested change
ENV = os.environ
environment = os.environ.copy()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if so, git checkout should not be called at all as someone might assume that the whole traffic is transported over configured proxy and I think subprocess will not use monkeypatched sockets. Perhaps adding optional flag --git-checkout with a proper explanation would suffice.

Copy link
Owner

@arthaud arthaud Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think there is a misunderstanding.
We should definitely call git checkout . with the modified environment. I'm just saying we shouldn't modify os.environ in case it's used somewhere else. TL, DR: Just add a .copy() to os.environ.

git_dumper.py Outdated
subprocess.check_call(["git", "checkout", "."])
ENV = os.environ
configured_proxy = socks.getdefaultproxy()
if configured_proxy[0] > 0:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if there are no proxy configured? It looks like configured_proxy would be None.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it's indeed a None type, so changing 490 line to:

if configured_proxy != None:

should not raise exception in case of no proxy is set. I thought I tested a no proxy usage but looks like I didn't.

["git", "checkout", "."],
stderr=open(os.devnull, "wb"),
env=ENV
)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ENV is only created within that if line 469 so it wouldn't exist here (since that if returns).
We also need to sanitize the .git/config here.
We could move the whole git checkout step in a function to avoid code duplication.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment wasn't addressed.
Notice how the if line 450 implements a different stategy where we just download recursively using directory indexing, but if that if is not taken, we use a different strategy. In that case, you are not sanitizing the .git/config and you are not setting up the environment variable either.
We need two changes:

  • Move the environment variable creation and setup before the if line 450
  • Add a Sanitizing .git/config step here (line 647) before calling git checkout .

Copy link
Owner

@arthaud arthaud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(wrongly clicked on Approve above)

["git", "checkout", "."],
stderr=open(os.devnull, "wb"),
env=ENV
)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment wasn't addressed.
Notice how the if line 450 implements a different stategy where we just download recursively using directory indexing, but if that if is not taken, we use a different strategy. In that case, you are not sanitizing the .git/config and you are not setting up the environment variable either.
We need two changes:

  • Move the environment variable creation and setup before the if line 450
  • Add a Sanitizing .git/config step here (line 647) before calling git checkout .

@srozb
Copy link
Contributor Author

srozb commented Mar 4, 2024

Please take another look at changed source, as I'm not 100% sure if I picked the correct line to move the environment creation to.

I think eventually it'd be better to move the ALL_PROXY env variable creation just after the pysocks proxy is set up and ensure every subprocess call is taken with env=environment argument. It'd also be nice to bound sanitization with checkout putting it together in separate function.

(thinking out loud)

@arthaud arthaud merged commit 1df41e9 into arthaud:master Mar 5, 2024
@arthaud
Copy link
Owner

arthaud commented Mar 5, 2024

Great, thanks for contributing!


with open(filepath, 'r+') as f:
content = f.read()
modified_content = re.sub(UNSAFE, '# \g<0>', content, flags=re.IGNORECASE)
Copy link
Contributor

@ZanyMonk ZanyMonk Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @srozb, thanks for taking the time to fix this. However there is a few issues with your current patch.

  1. This line lacks a | re.MULTILINE. In the current state it only works if the payload is the first line (which never happens).

  2. One can bypass the regex with this syntax:

[core]
       ...
[core] fsmonitor = "sh -c '...'"
  1. As stated by the owner in the issue I opened, it would be much simpler and safer to (re)move .git/config, since we don't need it to run git checkout . IIRC.

    That is because it's possible to use many other git features to leverage RCE, for example one could [include] another file from the $GIT_DIR. This would defeat your patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants