From f528bb9846274747c48fc24758b77505f90b01c0 Mon Sep 17 00:00:00 2001 From: Steven McDonald Date: Fri, 21 Sep 2018 18:02:16 +0200 Subject: [PATCH] Add --no-sudo-pythonpath option This provides a way to avoid setting PYTHONPATH when invoking the privileged part of sshuttle with sudo. This is useful if running sshuttle as a PEX archive, as Telepresence does, as it enables sshuttle's sudo access to be securely locked down. PEX archives will extract themselves into the invoking user's home directory, which means that the invoking user has full control over the code in them. This makes restricting sudo access with PYTHONPATH set completely pointless in this scenario -- an attacker could put any code into ~/.pex and gain full root access anyway. On the other hand, if sshuttle is a PEX archive, the privileged invocation will simply extract itself into /root/.pex anyway, so there is no need to set PYTHONPATH in this case. --- sshuttle/client.py | 14 ++++++++------ sshuttle/cmdline.py | 3 ++- sshuttle/options.py | 8 ++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/sshuttle/client.py b/sshuttle/client.py index 4422e0e..98abcae 100644 --- a/sshuttle/client.py +++ b/sshuttle/client.py @@ -183,7 +183,7 @@ class MultiListener: class FirewallClient: - def __init__(self, method_name): + def __init__(self, method_name, sudo_pythonpath): # Default to sudo unless on OpenBSD in which case use built in `doas` elevbin = 'sudo' @@ -198,10 +198,12 @@ class FirewallClient: ['--firewall']) if ssyslog._p: argvbase += ['--syslog'] - elev_prefix = [part % {'eb': elevbin, 'pp': python_path} + elev_prefix = [part % {'eb': elevbin} for part in ['%(eb)s', '-p', - '[local %(eb)s] Password: ', - '/usr/bin/env', 'PYTHONPATH=%(pp)s']] + '[local %(eb)s] Password: ']] + if sudo_pythonpath: + elev_prefix += ['/usr/bin/env', + 'PYTHONPATH=%s' % python_path] argv_tries = [elev_prefix + argvbase, argvbase] # we can't use stdin/stdout=subprocess.PIPE here, as we normally would, @@ -550,7 +552,7 @@ def main(listenip_v6, listenip_v4, ssh_cmd, remotename, python, latency_control, dns, nslist, method_name, seed_hosts, auto_hosts, auto_nets, subnets_include, subnets_exclude, daemon, to_nameserver, pidfile, - user): + user, sudo_pythonpath): if daemon: try: @@ -560,7 +562,7 @@ def main(listenip_v6, listenip_v4, return 5 debug1('Starting sshuttle proxy.\n') - fw = FirewallClient(method_name) + fw = FirewallClient(method_name, sudo_pythonpath) # Get family specific subnet lists if dns: diff --git a/sshuttle/cmdline.py b/sshuttle/cmdline.py index 870fdd7..907e7cf 100644 --- a/sshuttle/cmdline.py +++ b/sshuttle/cmdline.py @@ -76,7 +76,8 @@ def main(): opt.daemon, opt.to_ns, opt.pidfile, - opt.user) + opt.user, + opt.sudo_pythonpath) if return_code == 0: log('Normal exit code, exiting...') diff --git a/sshuttle/options.py b/sshuttle/options.py index 6810f3c..e158350 100644 --- a/sshuttle/options.py +++ b/sshuttle/options.py @@ -310,3 +310,11 @@ parser.add_argument( (internal use only) """ ) +parser.add_argument( + "--no-sudo-pythonpath", + action="store_false", + dest="sudo_pythonpath", + help=""" + do not set PYTHONPATH when invoking sudo + """ +)