Skip to content

Commit

Permalink
Add ssh -L / ssh.connect_remote() workaround when `AllowTcpForwar…
Browse files Browse the repository at this point in the history
…ding` 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.
  • Loading branch information
peace-maker committed Jan 30, 2025
1 parent 3eb690b commit f698f6c
Showing 1 changed file with 21 additions and 0 deletions.
21 changes: 21 additions & 0 deletions pwnlib/tubes/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,14 +441,34 @@ def __init__(self, parent, host, port, *a, **kw):
# keep the parent from being garbage collected in some cases
self.parent = parent

# keep reference to tunnel process to avoid garbage collection
self.tunnel = None

self.host = parent.host
self.rhost = host
self.rport = port

import paramiko.ssh_exception
msg = 'Connecting to %s:%d via SSH to %s' % (self.rhost, self.rport, self.host)
with self.waitfor(msg) as h:
try:
self.sock = parent.transport.open_channel('direct-tcpip', (host, port), ('127.0.0.1', 0))
except paramiko.ssh_exception.ChannelException as e:
# Workaround AllowTcpForwarding no in sshd_config
if e.args != (1, 'Administratively prohibited'):
self.exception(str(e))
raise e

self.debug('Failed to open channel, trying to connect to remote port manually using netcat.')
if parent.which('nc'):
ncat = 'nc'
elif parent.which('ncat'):
ncat = 'ncat'
else:
self.exception('Could not find ncat or nc on remote. Cannot connect to remote port.')
raise
self.tunnel = parent.process([ncat, host, str(port)])
self.sock = self.tunnel.sock
except Exception as e:
self.exception(str(e))
raise
Expand Down Expand Up @@ -949,6 +969,7 @@ def process(self, argv=None, executable=None, tty=True, cwd=None, env=None, igno
self.upload_data(script, tmpfile)
return tmpfile

executable = executable or argv[0]
if self.isEnabledFor(logging.DEBUG):
execve_repr = "execve(%r, %s, %s)" % (executable,
argv,
Expand Down

0 comments on commit f698f6c

Please sign in to comment.