Port Forwarding
SSH Tunneling
First, add this to your SSH config if you want to avoid the host key prompt:
Host *
ServerAliveInterval 60
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
::: note
The convention I'll be using is $LOCAL_X
to refer to your local machine/ports and $REMOTE_X(_N)?
to refer to remote machines/ports.
:::
Local Port Forwarding (I need to reach a specific service via a jumpbox)
Let's say we want to reach a service running on $REMOTE_HOST_2
, but we can only access it via $REMOTE_HOST_1
. We can set up a local SSH tunnel that starts a listening port on our machine, which will have all of its traffic forwarded to the service on $REMOTE_HOST_2
via $REMOTE_HOST_1
.
ssh -N -L 0.0.0.0:$LOCAL_PORT:$REMOTE_HOST_2:$REMOTE_PORT_2 $REMOTE_USER_1@$REMOTE_HOST_1
Another use of this is to gain access to a service listening only on the localhost
interface of $REMOTE_HOST_1
:
ssh -N -L 0.0.0.0:$LOCAL_PORT:127.0.0.1:$REMOTE_PORT_1 $REMOTE_USER_1@$REMOTE_HOST_1
For a more complex scenario, let's say we want to reach a service running on $REMOTE_HOST_3
, but we can only access it via $REMOTE_HOST_2
. If we can reach $REMOTE_HOST_2
from $REMOTE_HOST_1
, then we can set up a port listening on $REMOTE_HOST_1
and forward all traffic destined for that port to the service on $REMOTE_HOST_3
via $REMOTE_HOST_2
:
ssh -N -L 0.0.0.0:$REMOTE_PORT_1:$REMOTE_HOST_3:$REMOTE_PORT_3 $REMOTE_USER_2@$REMOTE_HOST_2
Reverse Port Forwarding (another host needs to reach my host and/or network)
We may not be able to set up a local or dynamic port forward on a machine due to connectivity issues (i.e. the newly-created remote port may be blocked by a firewall). Instead, we can "send" a port forward to our local machine from the remote host instead and access the unreachable service via that local port:
ssh -N -R 127.0.0.1:$LOCAL_PORT:$REMOTE_HOST_2:$REMOTE_PORT_2 $LOCAL_USER@$LOCAL_HOST
Beyond pentesting, this is also useful for the reverse scenario where we want to expose local resources to a remote machine (disclaimer: in the vast majority of situations, this isn't a good approach!):
ssh -N -R 0.0.0.0:$REMOTE_PORT_1:$REMOTE_HOST_2:$REMOTE_PORT_2 $LOCAL_USER@$LOCAL_HOST
Dynamic Port Forwarding (all of my network traffic needs to originate from another host)
Let's say we want to access an entire network that's unreachable from our current machine. We can use dynamic port forwarding to set up a SOCKS proxy server that we point traffic towards:
ssh -N -D 0.0.0.0:$LOCAL_PORT $REMOTE_USER@$REMOTE_HOST
Now we can combine proxychains with, say, curl to access the network:
proxychains curl http://$UNREACHABLE_HOST/
This also works if the port is listening on a remote host (i.e. more than one jumpbox and/or missing SSH access), but you'll need to edit the proxychains config file as well.
If you need to use authentication, IPv6, and/oror UDP, then make sure proxychains is configured to use SOCKS5 (SSH supports this, but do note that not all SOCKS servers support this).
Port Scanning
If you use proxychains for port scanning in this setup, lower the default configuration values for tcp_read_time_out
and tcp_connect_time_out
. The default values are very high, which makes port scanning very slow.
WARNING
Proxychains doesn't work with binaries that have been statically-compiled. It uses LD_PRELOAD
to hook libc
networking functions to force all connections through the connection server, so as a result, proxychains only works for dynamically-compiled binaries.
Remote Dynamic Port Forwarding
::: note
This functionality requires OpenSSH client 7.6+.
:::
This one is pretty simple, just combine the concepts of remote and dynamic port forwarding to get a powerful tool.
ssh -N -R $LOCAL_PORT $LOCAL_USER@$LOCAL_HOST
Just like with reverse port forwarding, we can also use this technique to expose local resources to a remote host (again, you should have a very good reason for doing this):
ssh -N -R $REMOTE_PORT $REMOTE_USER@$REMOTE_HOST
socat
To forward packets to a remote port:
socat -ddd TCP-LISTEN:$LOCAL_PORT,fork TCP:$REMOTE_HOST:$REMOTE_PORT