Skip to content

Commit f698f6c

Browse files
committed
Add ssh -L / ssh.connect_remote() workaround when AllowTcpForwarding is disabled
Use a netcat process on the remote to connect to the specified host:port and tunnel the traffic using normal `ssh.process` I/O. This was inspired by the "Circumventing Disabled SSH Port-Forwarding with a Multiplexer" article by @guysv in the Paged Out! zine no. 5. It allows to use `gdb.debug(arg, ssh=ssh)` to debug processes on pwn.college.
1 parent 3eb690b commit f698f6c

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

pwnlib/tubes/ssh.py

+21
Original file line numberDiff line numberDiff line change
@@ -441,14 +441,34 @@ def __init__(self, parent, host, port, *a, **kw):
441441
# keep the parent from being garbage collected in some cases
442442
self.parent = parent
443443

444+
# keep reference to tunnel process to avoid garbage collection
445+
self.tunnel = None
446+
444447
self.host = parent.host
445448
self.rhost = host
446449
self.rport = port
447450

451+
import paramiko.ssh_exception
448452
msg = 'Connecting to %s:%d via SSH to %s' % (self.rhost, self.rport, self.host)
449453
with self.waitfor(msg) as h:
450454
try:
451455
self.sock = parent.transport.open_channel('direct-tcpip', (host, port), ('127.0.0.1', 0))
456+
except paramiko.ssh_exception.ChannelException as e:
457+
# Workaround AllowTcpForwarding no in sshd_config
458+
if e.args != (1, 'Administratively prohibited'):
459+
self.exception(str(e))
460+
raise e
461+
462+
self.debug('Failed to open channel, trying to connect to remote port manually using netcat.')
463+
if parent.which('nc'):
464+
ncat = 'nc'
465+
elif parent.which('ncat'):
466+
ncat = 'ncat'
467+
else:
468+
self.exception('Could not find ncat or nc on remote. Cannot connect to remote port.')
469+
raise
470+
self.tunnel = parent.process([ncat, host, str(port)])
471+
self.sock = self.tunnel.sock
452472
except Exception as e:
453473
self.exception(str(e))
454474
raise
@@ -949,6 +969,7 @@ def process(self, argv=None, executable=None, tty=True, cwd=None, env=None, igno
949969
self.upload_data(script, tmpfile)
950970
return tmpfile
951971

972+
executable = executable or argv[0]
952973
if self.isEnabledFor(logging.DEBUG):
953974
execve_repr = "execve(%r, %s, %s)" % (executable,
954975
argv,

0 commit comments

Comments
 (0)