How to ssh forwarding with AllowTcpForwarding set to no?
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:
Replace ProxyJump with Bash
The idea above is good! Here is my generic ssh_config version when ProxyJump is not working because AllowTcpForwarding set to no and my default shell is BASH:
ProxyCommand=ssh -T user1@gateway "exec 3<>/dev/tcp/%h/%p 2<&- ; cat <&3 & cat >&3 ; kill $!"
- -T Disable pseudo-terminal allocation
- exec No new process (bash) will be created
- 3<> is simply redirection to an available file descriptor
- /dev/tcp/... will ask bash to open the corresponding TCP socket.
- %h and %p will be evaluated by your OpenSSH client as devbox and 22
- 2<&- will close the STDERR (you could also redirect it to /dev/null)
- cat <&3 & will read the selected file descriptor 3 in the background
- cat >&3 will write our file descriptor in the foreground
- kill $! will kill the "reading" cat <&3 command running in the background when you close/broke the connection. Otherwise it would keep running.
It could replace ProxyJump for me in situations when it was disabled on the jump server but I really didn't wanted to forward my private key there or enter any passwords without an extra level of encryption. Using others SSH_AUTH_SOCK as root or record terminal sessions completely with keystrokes are both real things.
But please, always make sure you don't violate any policies that apply to you!