Shell – How to ssh forwarding with AllowTcpForwarding set to no

linuxpythonshellsshssh-tunneling

There is some development I need to do on some remote box. Fortunately, I have shell access, but I need to go through a gateway that has AllowTcpForwarding set to false.

I took a peak at the docs and it says:

AllowTcpForwarding Specifies whether TCP forwarding is permitted. The
default is ''yes''. Note that disabling TCP forwarding does not
improve security unless users are also denied shell access, as they
can always install their own forwarders.

How would I go about installing (or building) my own forwarder? My goal here is to setup a remote interpreter using Pycharm via SSH and binding it to some local port, that data fed through ssh, that through the gateway, and then to the development box where the code is actually run. I imagine I could somehow utilize nc or some other unix utility that'll help get the job done.

I know I can ssh to my remote box by doing:

ssh -t user1@gateway ssh user2@devbox

But obviously this option isn't available in pycharm. I'll have to be able to open some local port such that

ssh -p 12345 localhost
(or variant)

will connect me to user2@devbox. This will allow me to configure the remote interpreter to use port 12345 on localhost to connect to the remote box.

Best Answer

As long as one can execute socat locally and on gateway (or even just bash and cat on gateway, see last example!) and is allowed to not use a pty to be 8bits clean, it's possible to establish a tunnel through ssh. Here are 4 examples, improving upon the previous:

Basic example working once

(having it fork would require one ssh connection per tunnel, not good). Having to escape the : for socat to accept the exec command:

term1:

$ socat tcp-listen:12345,reuseaddr exec:'ssh user1@gateway exec socat - tcp\:devbox\:22',nofork

term2:

$ ssh -p 12345 user2@localhost

term1:

user1@gateway's password:

term2:

user2@localhost's password: 

Reversing first and second addresses makes the socket immediately available

socat has to stay in charge, so no nofork:

term1:

    $ socat exec:'ssh user1@gateway exec socat - tcp\:devbox\:22' tcp-listen:12345,reuseaddr
    user1@gateway's password:

term2:

    $ ssh -p 12345 user2@localhost
    user2@localhost's password:

Using a ControlMaster ssh

allows to fork while using only a single ssh connection to the gateway, thus giving a behaviour similar to the usual port forwarding:

term1:

    $ ssh -N -o ControlMaster=yes -o ControlPath=~/mysshcontrolsocket user1@gateway
    user1@gateway's password:

term2:

    $ socat tcp-listen:12345,reuseaddr,fork exec:'ssh -o ControlPath=~/mysshcontrolsocket user1@gateway exec socat - tcp\:devbox\:22'

term3:

    $ ssh -p 12345 user2@localhost
    user2@localhost's password:

Having only bash and cat available on gateway

By using bash's built-in tcp redirection, and two half-duplex cat commands (for a full-duplex result) one doesn't even need a remote socat or netcat. Handling of multiple layers of nested and escaped quotes was a bit awkward and can perhaps be done better, or simplified by the use of a remote bash script. Care has to be taken to have the forked cat for output only:

term1 (no change):

$ ssh -N -o ControlMaster=yes -o ControlPath=~/mysshcontrolsocket user1@gateway
user1@gateway's password:

term2:

$ socat tcp-listen:12345,reuseaddr,fork 'exec:ssh -T -o ControlPath=~/mysshcontrolsocket user1@gateway '\''exec bash -c \'\''"exec 2>/dev/null 8<>/dev/tcp/devbox/22; cat <&8 & cat >&8"\'\'\'

term3:

$ ssh -p 12345 user2@localhost
user2@localhost's password:
Related Question